반응형

https://www.acmicpc.net/problem/5622

 

알파벳 별로 매핑되는 int값을 구하는 로직을 구현하는 것이 핵심이 문제다.

다양한 방법이 있을 거 같은데, 나는 (하드코딩 + 선형탐색)이라는 단순한 방식으로 lookup table 함수를 만들었다.

 

정답 코드

from functools import reduce


def lut(c):
    groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"]
    for i, g in enumerate(groups):
        if c in g:
            return i + 3


print(reduce(lambda x, y: x + lut(y), input(), 0))

 

lut의 결과인 정수값들의 총합을 구하기 위해 functoolsreduce를 처음 써봤다. JavaScript의 reduce와 비슷하게 동작한다. 

reduce 사용시 Accumulation의 초기값(0)을 잘 세팅하는 것이 중요하다.

반응형
반응형

https://www.acmicpc.net/problem/11720

 

문자열로 입력이 들어오는 모든 개별 1자리 단위 숫자를 합해서 출력하는 간단한 문제다.

 

정답 코드

import sys

next(sys.stdin)
s = list(next(sys.stdin))[:-1]
print(sum(int(i) for i in s))

 

간단한 문제이지만, 따로 블로그로 기록을 남기게 된 이유는 아래 문구를 사용하면서 새로 배운 게 있기 때문이다.

sum(int(i) for i in s)

먼저 VS Code에서 sum 함수에 대한 설명을 보면, 첫째 인자로 iterable을 받는다는 것을 알 수 있다.

그말인즉슨 sum() 안의 int(i) for i in s 가 iterable이라는 뜻이다. 엄밀히 말하면 generator이다.

여태까지는 x for x in y 형태의 표현이 generator이다라는 것을 생각 안하고 사용해왔다.

이러한 x for x in y 형태의 generator 표현법을 "Generator Expression"이라고 한다.

아래에서 확인 가능하다.

print(type(i for i in range(5))) # 출력: <class 'generator'>
print(i for i in range(5)) # 출력: <generator object <genexpr> at 0x0000014C60D77400>

generator는 iterable이기도 하므로, generator expression도 list(), [], tuple() 등으로 감싸서 사용할 수 있다.

또한 map()등에도 전달할 수 있다.

print(list(i for i in range(5))) # 출력: [0, 1, 2, 3, 4]
print([i for i in range(5)]) # 출력: [0, 1, 2, 3, 4]
print(tuple(i for i in range(5))) # 출력: (0, 1, 2, 3, 4)
print(list(map(lambda x : x * 2, (i for i in range(5))))) # 출력: [0, 2, 4, 6, 8]

 

중요한 점 

x for x in y 형태의 generator expression은 함수의 인자로 전달될 때만 유효한 표현이고, 인자가 아닌 독립적인 형태로 존재하려면 괄호로 감싸서 (x for x in y) 형태여야 한다.

함수의 인자로 전달되는 generator expression은 괄호로 감싸지 않아도 파이썬이 generator expression인 것으로 알아서 처리하는 한다.

반면, 독립적으로 존재하는 generator expression은 괄호로 감싸지 않으면 아래처럼 SyntaxError가 발생하는 것을 확인할 수 있다. 에러 문구에서도 괄호로 감싸라고 친절히 알려주고 있다.

print(map(lambda x : x * 2, i for i in range(5)))
  File "<stdin>", line 1
    print(map(lambda x : x * 2, i for i in range(5)))
                                ^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized

아래처럼 괄호로 감싸야 에러가 발생하지 않는다.

print(map(lambda x : x * 2, (i for i in range(5)))) # 출력: <map object at 0x0000014C60FA9D20>
반응형
반응형

https://www.acmicpc.net/problem/10807

 

문제 자체는 배열 안에 요소의 갯수를 세는 매우 간단한 문제다.

 

정답 코드

import sys

next(sys.stdin)
s = next(sys.stdin).split()
v = next(sys.stdin).rstrip("\n")
sys.stdout.write(f"{s.count(v)}")

그렇지만 문제를 풀때 stdin을 사용해서 입력을 처리하다보니 궁금한 점이 생겼다.

28278번 문제 같은 경우, 데이터 입력시 마지막에 Ctrl+Z를 입력해서 입력 스트림 종료(EOF)를 명시적으로 전달해야 했다.

그러나 위 코드의 경우 Ctrl+Z를 입력할 필요가 없었다.

그 이유는 3번째 next()가 호출될 때, 코드 입장에서 stdin으로부터 필요한 모든 데이터를 이미 읽었기 때문이다. 이후에는 코드에서 next()를 추가로 호출하지 않고 있다. 그래서 애초에 EOF가 있는지 여부를 검사하는 과정이 필요가 없다.

즉, next()가 코드에서 미리 정한 횟수(3번)만큼은 호출되므로, next() 호출시 EOF가 검출되는지 여부를 검사하는 로직 자체가 필요 없는것이다.

반면에, 28278번 문제의 경우는 for 문에서 stdin을 계속해서 반복해서 읽으려고 한다. 이때 next() 호출시 EOF가 검출되는 것이 확인되어야 for 문이 종료된다. 

반응형
반응형

https://www.acmicpc.net/problem/28278

 

스택을 구현하고, 입력되는 명령에 따라 스택에 아이템 추가/삭제/조회 를 수행하는 프로그램을 구현해야 한다.

 

결과 문자열을 result에 저장하는 아래의 코드를 제출했으나 시간 초과가 발생했다.

시간 초과 발생 코드

import sys

commands = [s.rstrip("\n") for s in sys.stdin.readlines()][1:]
stack = []
result = ""
for command in commands:
    if command[0] == "1":
        num = int(command[2:])
        stack.append(num)
    elif command[0] == "2":
        result += f"{stack.pop() if stack else -1}\n"
    elif command[0] == "3":
        result += f"{len(stack)}\n"
    elif command[0] == "4":
        result += f"{0 if stack else 1}\n"
    elif command[0] == "5":
        result += f"{stack[-1] if stack else -1}\n"

sys.stdout.write(result)

조사해보니, 시간 초과가 발생하는 이유는 다음과 같다.

for 루프에서 매번 +=를 사용해 result 문자열에 append를 할 때마다 완전히 새로운 result 문자열 객체가 생성되기 때문이다.

예를 들어 아래 코드가 수행되면 무슨 일이 벌어질는지 알아보자.

result += f"{stack.pop() if stack else -1}\n"
  1. f"{stack.pop() if stack else -1}\n" 부분은 새로운 임시 문자열을 생성한다.
  2. result += ... 부분의 += 연산은 under the hood에서 다음 동작을 수행한다
    • 이전의 result 문자열과 새로운 임시 문자열을 결합한 새로운 문자열이 메모리 공간에 새로 할당된다.
    • 이전의 result 문자열과 임시 문자열의 메모리 공간이 해제된다.

즉 += 연산이 발생할 때마다 result 문자열 전체에 대한 메모리에 재할당 및 복사 작업이 발생하는 것이다. 이 과정은 result 문자열이 길어지면 길어질 수록 점점 더 비용이 증가한다. 

대신에 결합할 문자열들을 list에 모아두었다가, 마지막에 join() 연산을 통해 한번에 결합하는 것이 비용을 아낄 수 있다.

 

출력할 결과 문자열을 모두 result라는 list에 모아두었다가, 마지막에 "\n".join(rsult)를 출력하도록 했다.

정답 코드

import sys

commands = [s.rstrip("\n") for s in sys.stdin.readlines()][1:]
stack = []
result = []
for command in commands:
    if command[0] == "1":
        stack.append(command[2:])
    elif command[0] == "2":
        result.append(stack.pop() if stack else "-1")
    elif command[0] == "3":
        result.append(str(len(stack)))
    elif command[0] == "4":
        result.append("0" if stack else "1")
    elif command[0] == "5":
        result.append(stack[-1] if stack else "-1")

sys.stdout.write("\n".join(result))

 

추가 최적화를 진행해봤다.

sys.stdin.readlines()는  list를 새로 생성해서 반환하기 때문에, 리스트를 만드는 시간 비용과 메모리 공간 비용을 절감해봐야 겠다고 생각했다.

sys.stdin이 파일 객체처럼 동작하므로 곧 iterable이라는 점을 이용했다. 즉 for 루프나 iterator protocol을 이용 가능하다는 의미이다. (이와 관련해서는 https://comgu.tistory.com/entry/Python-Iteration의-원리Iterator-Protocol 참고)

입력의 첫줄은 필요 없기 때문에 next()로 읽은 다음 버리고, 그 다음 줄부터 for 문으로 순회하도록 했다.

추가 최적화된 정답 코드

import sys

stack = []
result = []
next(sys.stdin)
for s in sys.stdin:
    command = s.rstrip("\n")
    if command[0] == "1":
        stack.append(command[2:])
    elif command[0] == "2":
        result.append(stack.pop() if stack else "-1")
    elif command[0] == "3":
        result.append(str(len(stack)))
    elif command[0] == "4":
        result.append("0" if stack else "1")
    elif command[0] == "5":
        result.append(stack[-1] if stack else "-1")

sys.stdout.write("\n".join(result))

메모리 사용은 절반 정도, 시간도 10% 절감했다.

결과적으로 sys.stdin.readlines()로 신규 list를 생성하지 않아도 되었기 때문이다.

반응형
반응형

저는 6년 좀 안되게 삼성전자 시스템LSI사업부에서 소프트웨어 엔지니어로 근무했었습니다. Linux Device Driver 개발을 수년간 했고, 사내 웹서비스의 풀스택 개발을 잠시 했었습니다.

그리고 퇴사 후 반년 정도 스타트업에서 근무했고, 6개월 정도 일을 쉬었다가, 현재는 다시 개발자로 취업하기 위해 공부 중입니다.

수년간 두 상반된 개발자 조직에 있으면서 생각하곤 했던 "좋은 개발자 되기, 그리고 개발자로 취업시 고려할 점"에 대해서 한번 정리해보려고 합니다.

 

ChatGPT 이미지 생성 - 개발자 커리어

 

1. 스스로 못한다고 생각하지 말자.

많은 개발자들은 가면 증후군(Imposter Syndrome)이라는 것을 갖고 있다고 합니다. https://en.wikipedia.org/wiki/Impostor_syndrome

 

Impostor syndrome - Wikipedia

From Wikipedia, the free encyclopedia Psychological pattern Medical condition Impostor syndrome, also known as impostor phenomenon or impostorism, is a psychological experience in which a person suffers from feelings of intellectual and/or professional fra

en.wikipedia.org

 

가면 증후군이란, 업무에서 자신의 능력을 의심하고 성과에 대해서 과소평가하는 것입니다. 자신이 일을 잘한다고 동료들을 속이는 사기꾼이라는 느낌을 받곤 합니다. 

아래와 같은 생각을 하고 있다면 가면 증후군에 해당될 수 있다고 합니다:

  • "나는 개발자가 될만큼 머리가 좋지 않은 것 같아"
  • "동료들보다 실력이 떨어지는 것 같아"
  • "일도 해야 되고 개발 공부도 해야 되는데 벅차고 힘들다"
  • "누군가 나의 진짜 실력을 알아챌까봐 두렵다"

개발자들은 워낙 업무의 지식적 범위가 넓고 개개인의 퍼포먼스가 다른 직종에 비해 좀 더 명확하게 드러나므로, 가면 증후군에 매우 취약한 직종이라고 생각합니다.

저 또한 오랫동안 겪어왔던 문제였고 번아웃 증상을 여러 번 겪었습니다. 일의 난이도는 높고, 너무 많은 일에 허덕였었고, 주변에 뛰어난 동료들이 너무 많아서 더 그랬던 것 같습니다. 제가 일을 쉬게 된 큰 이유 중 하나였던 것 같습니다.

 

코딩을 잘하는 사람은 정말 많습니다. 그런 사람들이 주목을 많이 받기도 하고, 실제로 좋은 대접을 받는 것도 사실입니다.

하지만 정작 업계에서는 그 실력자들보다 더 많은 사람들이 근무하고 있습니다. 개발자 대부분은 평범한 사람들이고, 회사에서는 실력 있는 사람을 구하지 못해서 문제라고 합니다. 많은 사람들이 현 상태에 지쳐 안주하거나 포기하기 때문에 회사가 원하는 수준까지 도달 못한다고도 생각이 듭니다.

중요한 것은 내 실력을 열심히 기르면서, 내가 할 수 있는 일을 하는 것입니다. 꾸준하게 실력을 기르다 보면, 어느샌가 실력이 쌓여 있을 것이고, 그때 내 실력에 맞는 직장이나 일감을 구하면 된다고 생각합니다.

내 실력에 비해 지나친 연봉 및 처우에 대한 욕심을 버리지 못하면, 번아웃 및 가면 증후군에 걸릴 위험이 크다고 느낍니다.

저는 멘탈이 건강한 실력자가 되는 것이 목표입니다.

 

2. 끊임없이 공부하고 정리하고 기록해야 내 것이 된다.

개발자로서 알아야 되는 지식은 너무나도 광범위합니다. 수많은 개발자들이 끝없는 학습량에 압도당하는 일이 잦기 때문에 스트레스를 느끼고 저 또한 늘 그랬던 것 같습니다. 공부 자체는 개발자의 업이기 때문에 피할 수는 없습니다.

다행히 요즘은 구글링은 물론이고 LLM에 물어보면서 학습하는 것이 큰 도움이 됩니다. 그래서 질문에 대한 답을 얻는 것이 매우 용이해졌습니다.

그러나 제일 지양해야 하는 점은, 무엇인가에 대한 해답을 얻었을 때 당장의 문제를 넘기기 위해 1회성으로 당장 닥친 일만 처리하고 넘기는 것이라고 생각합니다.

먼저 해답이 왜 해답인지에 대한 이해를 어느정도 확실히 해두고, 어딘가에 정리하고 기록을 해서 보관을 하는 것이 필요합니다. 왜냐하면 개발 지식이라는 것은 조만간 다시 재사용이 필요한 경우가 부지기수이기 때문에, 다음 번에 필요한 순간이 되었을 때 생각이 나는 것이 중요하고, 생각이 안 난다면 어디로 가서 다시 look-up해야 하는지 빨리 기억하는 것이 중요하기 때문입니다. 나만의 cheetsheat 공간이 필요합니다(제 블로그도 이런 비슷한 공간입니다).

당장 공부를 하고 기록한다는 것 자체가 시간이 너무 많이 뺏기기 때문에 비효율적이라고 느낄 수도 있습니다. 하지만 이것을 게을리 하면, 금방 물경력 개발자가 된다는 것을 몸소 느꼈습니다.

저도 계속해서 효율적인 정보 기록 방법을 계속 찾고자 노력 중입니다.

 

3. 개발 능력에는 코딩만이 아닌 협업과 소통 능력의 비중이 매우 크다.

이것은 학생 또는 취준생 때는 깨닫기 어려운 사실 중 하나입니다. 나 혼자의 페이스대로 열심히 하면 보상이 따라주는 시기이기 때문입니다. 제가  프로그래밍을 시작하게 된 계기 중 하나가, 사람들이랑 너무 얽히는 게 기빨리고 화면만 보는 게 편하다고 생각해서인 것도 있었습니다. 그렇지만 잘못 생각한 것이었습니다. 이제는 어떤 제품이든 솔루션이든 서비스이든 기업에서 상용화하는 것은 개발자가 혼자서 다 개발할 수 있는게 거의 없고 팀워크로 만들어집니다. Git과 Github이 그렇게 중시되는 것도, 형상관리의 이유도 있겠으나, 결국 팀워크를 위한 기반 도구이기 때문입니다. 내가 하고 있는 일을 동료에게 원활하게 전달하고 피드백을 받는 것이 기본입니다. 자기가 무슨 일을 하고 있는지 알아들을 수 있도록 제때 공유해야 합니다.

일단 공식적인 업무 미팅과 보고문서는 모든 직장인한테 그렇듯이 개발자에게도 너무 중요합니다. 저는 주니어 때 이걸 잘 깨닫지 못했었는데요. 그냥 제가 평소에 열심히 일하는 모습을 보고 있을테니, 업무 미팅과 보고문서에서는 대충 임하는 경향이 있었습니다. 말로 하고 문장으로 표현하는 것은 본업인 개발하기도 바쁜데 몹시 귀찮은 일이었기 때문입니다. 그러나 내가 하는 일이 무엇인지 남에게 제대로 설명하지 못하면, 아무리 일을 열심히 했어도 열심히 안 한 게 된다는 걸 깨닫게 되었습니다. 내가 하는 일을 위의 매니저와 동료들이 평가하게 되는데, 내가 무슨 일을 하는지 그분들이 이해를 잘 못하면 좋은 평가를 받기가 어렵기 때문입니다. 업무 설명과 보고 작업이 귀찮지만 이것도 본업이라는 것을 이해해야 합니다.

공식적인 미팅과 보고 외에 업무 일상에서의 소통도 매우 중요합니다. 개발 업무는 요구사항과 구현에 있어서 매우 명확한 의사전달이 중요합니다. 해야 하는 일에 대해서 언어적으로 표현을 잘하는 것은 필수적입니다. Slack과 같은 협업 툴이나 업무메신저를 사용하면서, 말을 간결하고 이해하기 쉽게 쓰는 것의 연습이 필요합니다. "개떡같이 말하면 개떡같이 알아듣는다"가 당연한 이치입니다.

또한 상대방을 배려하는 인성에 우러나오는 언어 사용이 중요하다고 생각합니다. 개발자들 특성상 성격이 매우 드라이하고 기계적인 언어를 쓰는 사람들이 많은데, 이것에 의해 상처받는 사람들이 꽤 많은 것으로 압니다. 특히 요즘에는 코드 리뷰를 통한 협업이 필수인데, 불필요하게 공격적인 리뷰는 갈등의 원인이 될 수 있습니다. 상대방이 주니어일수록 특히 더 배려해서 친절한 문장을 쓰는 것도 연습해야 된다고 생각합니다.

마지막으로 사소하다고 느껴질 수 있겠지만, 동료의 작은 호의에 감사함을 표현하고, 어떤 의견에도 리액션을 잘해주는 것도 필요하다고 생각합니다. 계속해서 좋은 기억으로 남는 동료들은 실력보다는 인성이 좋았던 사람들인 것 같습니다.

 

4. 취업 전략

개발자로서 취업 전략이란 것은, 수많은 요소에 따라 다르게 가져가야 된다고 느낍니다.

고려해봐야 할 요건들을 생각나는대로 나열해보면..

  1. 희망 연봉
  2. 신입 or 경력직
    • 경력직의 경우 직급은 어떻게 할지?
  3. 회사 규모
    • 대기업 vs 중견 vs 스타트업
  4. 사업 도메인
    • ex) IT서비스, AI, 제조업, 금융, 교육, 커머스, 의료, 엔터테인먼트 등.
    • 분야에 따라 연봉과 문화 등이 매우 상이함. 또한 개발외적으로 배워야할 도메인 지식이 매우 다름.
  5. 회사의 성장성 여부(산업 전망)
  6. 사용하게 될 기술 스택과 업무 범위
    • 내가 배운 걸 쓰게 될지?
    • 기존 코드 유지보수 업무와 신규 개발 간 비중이 얼마나 될지?
    • 내가 감당 가능한 업무인지?
  7. 조직 문화(회사 평판)
    • Harsh한 성과주의 문화 vs 포용적 문화
    • Hardcore 야근 불사 vs 워라밸
  8. 회사 복지
    • 식대 지원, 교육비 지원, 장비 지원 등.
  9. 출퇴근 거리 or 재택근무 여부
    • 체력과 삶의 질에 지대한 영향이 있음.
  10. etc.

 

취직할 회사를 찾는데 있어서 위의 요건들을 최대한 많이 고려해봐야 한다고 생각합니다.

당장 취직이 급하다고 어디든 합격하는데로 바로 가면 안 된다고 생각합니다. 특히 아쉬운 위치인 신입일 때, 이런 오류를 범할 수 있다고 생각합니다.

중요한 것은, 빠른 합격이 아니라 지속 가능한 회사생활이기 때문입니다. 이것은 대기업이든 스타트업이든, 연봉이 많던 적던 간에 다 마찬가지입니다. 위 요건들을 몇 개 만족하지 못하는 회사에 취직한다면 일을 하면서도 마음이 금방 어려워질 수 있고, 이른 퇴사로 이어질 수 있습니다. 나의 마음이 건강하고 편안하게 오래 다닐 수 있어야, 개발자로서의 역량 향상도 따라올 수 있다고 생각합니다. 

당장 대기업이나 잘 나가는 회사를 못 가도 괜찮다고 생각합니다. 더 작은 회사에서 실력 향상을 할 수 있다면, 오히려 경력직으로 이직하는 것이 더 쉬울 것입니다(어느 회사든 가성비 좋은 경력직을 선호합니다). 개발자는 다른 직종보다 개인의 노력으로 실력의 향상이라는 것 더 가능한 직종이기 때문입니다.

저도 이번에 그럴 생각이지만, 여유를 가지고 취직 준비를 하고자 합니다. 쉬엄쉬엄하겠다는 것이 아니라, 내 업무 역량이 어느 정도 갖춰질 때까지 최선을 다하면서, 위 요건들을 제 기준에서 많이 맞출 수 있는 회사를 찾으려고 합니다.

 

5. 회사 지원 TIP

저는 스타트업에 잠시나마 있으면서 채용 절차에 관여했던 적이 있었습니다(서류 검토 & 면접 참여).

제 주관적인 생각이지만, 서류 단계에서는 일단 시선을 잘 끌어당기는 게 중요한 것 같습니다. 나쁜 의미의 노이즈나 어그로를 끌라는 의미는 아니고, 검토하는 사람에게 긍정적인 인상을 남기는 게 중요하다는 뜻입니다. 부트캠프 출신 개발자가 워낙 많기 때문에, 작은 회사라 할지라도 지원 서류는 수십~수백장은 기본으로 들어옵니다. 채용 담당자 입장에서, 많은 지원서를 보지만 그 중에서 정말 눈길이 가는 것은 소수입니다. 일단 진부하거나 올드해보이는 서류는 바로 탈락입니다(나이가 많은 지원자일수록 조심해야 될 것 같습니다).

직장 생활 이력, 프로젝트 경험, 기술 스택 정보 등의 정보가 간결 및 깔끔하고, 핵심이 잘 담긴 지원서들이 살아남았던 거 같습니다. 이런 서류들은 핵심 전달 능력이 좋기 때문에 이해하기 쉽기 때문입니다(일도 잘하겠구나 싶은 느낌을 줍니다). 

힙해보이는 포트폴리오는 분명 좋은 영향이 있긴합니다만, 내가 담당하고 기여한 부분이 무엇인지 제대로 이해하고 설명하지 못한다면 면접에서 부메랑으로 돌아올 수 있습니다.

경력을 부풀려서 작성하는 것은 정말 나쁘다고 생각합니다. 일단 그렇게 부풀려서 입사한다 한들, 회사의 기대치만 높여서 일할 때 본인만 힘들 것입니다.

전체적으로는 서류이든 면접이든, 지원자가 개발자로 취직하기 위해 얼마나 진실되고 성실하게 살았는지를 봤던 것 같습니다. 그리고 회사 자체에 대해서 열심히 파악하려고 하는 자세가 보인다면 더 호감이라고 생각합니다.

그리고 특히 면접에서 매우 중요한 요소가 사람의 인상과 성격이었습니다. 이것은 회사의 조직문화 특성에 따라 다르긴 한데요, 똑똑해보이고 번쩍이는 타입을 좋아하는 곳이 있는 반면, 젠틀하고 유들유들한 타입을 좋아하는 곳으로 나뉜다고 생각이 듭니다. 이건 사실 결국 같이 일할 실무진들이 "같이 일하고 싶은 사람"을 선택하는 매우 인간적인 과정이므로, 어느 정도 운이 작용하는 것 같습니다. 

채용과정에서 지원자는 많지만, 정작 건실한 지원서는 소수였던 것으로 기억합니다. 이 점을 역이용하면, 남들보다 조금만 더 좋은 평가를 받아도 합격하기가 수월하겠다는 생각을 가지게 되었습니다.

 

6. 마무리

글을 쓰면서 스스로의 커리어 패스에 대해서 회고할 수 있었습니다. 그러면서 다시 스스로의 마인드셋을 점검할 수 있는 기회도 되었습니다.

핵심은... "꾸준히 실력을 늘리는, 좋은 인성을 갖춘, 건강한 멘탈의 개발자가 되자"인 것 같습니다.

글을 읽는 모든 개발자 및 개발자 지망생에게 도움이 되었으면 좋겠습니다.

반응형
반응형

CSS Box Model은 웹 디자인과 개발의 기반적인 개념이다. 웹페이지의 요소(element)들이 어떻게 구조화될지, 요소들 주변의 공간이 어떻게 분배할지를 결정한다. CSS Box Model을 이해하는 것은 요소들의 레이아웃과 모양을 제어하는데 핵심적으로 필요하다.

웹페이지에서 모든 요소는 하나의 직사각형의 "box"라는 것을 먼저 이해해야 한다.

이 box는 안쪽부터 다음 4가지 영역들로 구성된다.

 

CSS Box Model의 구성 요소

  1. Content
    • Text, image, 또는 다른 컨텐츠가 디스플레이되는 공간.
    • widthheight 속성을 변경해서 크기를 제어할 수 있다.
  2. Padding
    • Content와 Border 사이의 공간(즉 Content를 감싸는 공간).
  3. Border
    • Padding과 Content를 감싸는 테두리.
  4. Margin
    • 가장 바깥 쪽의 공간(즉 Border 바깥의 빈 공간이며 투명함).
    • 요소와 다른 요소 간의 공간을 만든다.

 

출처: https://dev.to/devneagu/css-tricks-changing-the-default-box-model-33ip

 

영역별 상세 속성 설정

  1. Content - width
    • width는 요소의 너비값을 의미한다.
    • 기본값은 Content 영역의 너비이지만, box-sizing 속성을 사용하면 Padding과 Border의 너비까지도 포함할 수 있다.
    • width를 미입력시, 값으로 auto가 지정된다. 이는 부모 요소의 너비를 기준으로 계산하는 기능이다.
    • Box 요소에서만 사용가능하고, Inline 요소에서는 작동하지 않는다(display 속성에 block, inline-block 설정시 작동).
    • https://developer.mozilla.org/en-US/docs/Web/CSS/width
  2. Content - height
    • height는 요소의 너비값을 의미한다.
    • 기본값은 auto이며, Content의 높이만큼으로 지정된다. 
    • Box 요소에서만 사용가능하고, Inline 요소에서는 작동하지 않는다(display 속성에서 block, inline-block 설정시 작동) .
    • https://developer.mozilla.org/en-US/docs/Web/CSS/height
  3. Padding - padding
  4. Margin - margin
    • margin 속성으로 요소 바깥의 공간의 공간 크기를 지정할 수 있다.
    • 값이 auto로 설정되어 있다면, 부모 container 요소의 가로 중간(horizontally center) 위치로 요소의 위치를 설정할 수 있다. 원리는, (부모 요소의 너비 - 요소의 너비)값을 요소의 좌우 양쪽에 고르게 양분하는 것이다.
    • margin-topmargin-rightmargin-bottommargin-left 로 각 방향의 Padding 값을 지정할 수도 있다.
    • https://developer.mozilla.org/en-US/docs/Web/CSS/margin
  5. Border -  border-width, border-style, border-color
    • border-width: 테두리의 두께를 지정한다. 
      • border-top-width, border-right-width, border-bottom-width, border-left-width: 방향별로 따로 설정할 수 있다.
    • border-style: 테두리의 스타일을 지정한다.
      • border-top-style, border-right- style, border-bottom-style, border-left- style: 방향별로 따로 설정할 수 있다.
    • border-color: 테두리의 색상을 지정한다.
  6. box-sizing
    • 요소의 전체 너비와 높이를 어떻게 계산할지 정의한다.
    • 요소의 너비에 Padding과 Border를 포함할지 말지를 결정한다.
    • 값이 content-box인 경우(default):
      • 너비와 높이에 Content의 너비와 높이만 포함되고, Padding과 Border의 너비 및 높이 값은 제외된다.
    • 값이 border-box인 경우:
      • 너비와 높이에 Content, Padding, Border가 모두 포함된다.
      • 요소의 전체 크기를 관리하기가 더 용이하다.
    • https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
.content-box {
    box-sizing: content-box;
    width: 200px;
    padding: 20px;
    border: 5px solid black;
}
  • 위의 content-box의 경우, 실제 렌더되는 전체 너비 = Content 200px + Padding 40px + Border 10px = 250px이다. 
.content-box {
    box-sizing: border-box;
    width: 200px;
    padding: 20px;
    border: 5px solid black;
}
  • 위의 boder-box의 경우, 실제 렌더되는 전체 너비 = Content + Padding + Border = 200px이다. 

 

이외에 border-radius 같은 속성도 있지만 여기서는 생략한다.

 

CSS Box Model의 구성 요소 예시 1 (Block 요소)

<div class="box">Hello World!</div>
.box {
  width: 200px;
  height: 100px;
  padding: 10px;
  border: 5px solid black;
  margin: 20px;
}
  • 요소(element)는 <div> tag이다. 해당 요소는 box 클래스로 스타일링된다.
  • Content는 <div> 안에 위치한 "Hello World!"이다.
  • Box(즉, 요소)는 다음을 포함한다:
    • Content: "Hello World!" 텍스트 영역이며, widthheight로 크기가 정해진다.
    • Padding: 10px로 설정된 공간이다.
    • Border: 5px 굵기이며, solid 스타일에 검정색이다.
    • Margin: 20px의 Border 바깥 공간이다.

브라우저에 렌더링된 화면과, 4가지 구성요소의 레이아웃은 아래와 같다:

 

CSS Box Model의 구성 요소 예시 2 (Inline 요소)

<span class="inline">Hello World!</span>
.inline {
    padding: 5px;
    border: 1px solid red;
    margin: 10px;
}
  • 요소(element)는 <span> tag이다. 해당 요소는 box 클래스로 스타일링된다.
  • Content는 <span> 안에 위치한 "Hello World!"이다.
  • Box(즉, 요소)는 다음을 포함한다:
    • Content: "Hello World!" 텍스트 영역이며, Content 자체의 크기로 크기가 결정된다.
      • 즉 widthheight 속성으로 크기가 결정되지 않으므로, block 요소와는 달리 명시하지 않는다.
    • Padding: 5px로 설정된 공간이다.
    • Border: 1px 굵기이며, solid 스타일에 빨간색이다.
    • Margin: 20px의 Border 바깥 공간이다.
      • Inline 요소의 경우, left/right margin은 Box Model에 완전히 영향을 미친다. 반면 top/bottom margin은 특이하게 동작한다. top/bottom margin은 inline 요소가 속한 line box에 적용되는데, inline 요소 자체의 높이를 직접 바꾸지는 않는다. (부모 요소가 block container이고, 다른 요소들이 없는 경우와 같이 Inline 요소 주위의 다른 레이아웃 조건에 따라 브라우저가 상하 margin을 반영하기도 한다).
      • 아래 우측 그림에서는 margin이 top/bottom에도 적용된 것 같이 나왔지만, 실제로는 아래 좌측 그림 처럼 left/right에만 적용되었다.

브라우저에 렌더링된 화면과, 4가지 구성요소의 레이아웃은 아래와 같다:

 

 

CSS Box Model과 Block 요소 및 Inline 요소 간의 관계

  1. Block 요소 특성 및 CSS Box Model과의 관계:
    • Block 요소는 수평 공간 전체를 차지한다.
    • Block 요소는  위아래로 정렬되며, 새로운 줄을 만든다.
    • Block 요소 예시: <div>, <p>, <h1>~<h6>, <section>
    • CSS Box Model의 모든 4가지 영역(Content, Padding, Border, Margin)이 적용된다.
      • 이는 Block 요소가 Box Model의 4가지 영역을 모두 사용할 수 있고, 그에 따라 요소의 전체 크기가 조정될 수 있다는 것을 의미한다. 이로 인해 요소의 전체 크기는 Content 크기(widthheight로 결정) 외에 Padding, Border, Margin 값으로 결정된 추가 크기를 합하여 결정된다는 뜻이다.
      • 위의 예시의 Block 요소의 전체 최종 크기를 계산해보면 아래와 같다:
        • 너비: 200px (Content) + 10px*2 (Padding 좌우) + 5px*2 (Border 좌우) + 20px*2 (Margin 좌우) = 270px
        • 높이: 100px (Content) + 10px*2 (Padding 위아래) + 5px*2 (Border 위아래) + 20px*2 (Margin 위아래) = 170px
      • 결론: Block 요소는 4가지 영역을 모두 사용해 배치 및 디자인을 구성할 수 있고, 각 영역이 최종 크기에 영향을 미친다.
  2. Inline 요소 특성 및 CSS Box Model과의 관계:
    • Inline 요소는 수평으로 정렬된다.
    • Inline 요소는  Content 크기만큼의 box를 가지며, 주변 요소와 같은 줄에 위치한다.
    • Inline 요소 예시: <span>, <a>, <strong>, <em>
    • CSS Box Model이 적용되지만, widthheight 속성을 명시적으로 설정할 수 없다.
      • Content 영역의 크기는 텍스트나 콘텐츠 자체의 길이와 높이에 따라 자동으로 결정된다.
        • 예를 들어, <span>의 Content 크기는 해당 텍스트의 글자 수와 폰트 크기에 따라 결정된다.
      • Inline 요소에도 Padding, Border, Margin이 적용된다.
        • Padding과 Border는 Content 영역을 기준으로 내부 공간과 테두리를 추가하고, Margin은 요소와 주변 요소 사이의 간격을 추가한다. 이러한 추가 영역은 Content 주위를 감싸며, Inline 요소가 차지하는 전체 공간 크기에 영향을 미친다.
      • 위의 예시의 inline 요소의 전체 최종 크기를 계산해보면 아래와 같다:
        • 너비: 86px (Content) + 5px*2 (Padding 좌우) + 1px*2 (Border 좌우) + 10px*2 (Margin 좌우) = 118px
          • 가정: 일반적인 Arial 폰트와 브라우저 기본값 폰트크기 16px로, Content의 너비를 86px로 어림잡았다.
        • 높이: 18px (Content) + 5px*2 (Padding 위아래) + 1px*2 (Border 위아래) + 0px (inline 요소의 Margin 위아래 값은 무시됨) = 30px
          • 브라우저 기본값 폰트크기 16px를 기준으로 Content의 높이를 약 18px로 어림잡았다.
      • 결론: Inline 요소는 Content 영역의 크기가 명시적으로 widthheight 속성에 의해 결정되지 않고, 요소 내부의 텍스트나 콘텐츠 크기에 따라 자동으로 정해진다. 이외의 Padding, Border, Margin(좌우)는 Inline 요소의 크기에 영향을 미친다.
반응형

'HTML&CSS' 카테고리의 다른 글

[HTML&CSS] Font 설정하기  (0) 2024.12.17
[HTML&CSS] HTML Boilerplate & HTML 기본 구조  (2) 2024.12.16
반응형

HTML 파일에서 CSS를 사용해 Font 스타일을 설정하는 방법을 2개 토픽으로 알아보자.

 

1. Google Fonts 와 같은 font 제공 서비스에서 제공하는 font에 대한 정보를 CSS 파일로 확보한 뒤 font 파일에 접근하기.

 

Google Fonts의 검색에서 "Gugi"를 선택해봤다. 우측의 "Get font"를 누른다.

Gugi 선택

 

우측의 Get embed code를 클릭한다.

Get embed code 선택

 

"Embed code in the <head> of your html" 밑의 코드를 복사해서 html 파일의 <head> 부분에 붙여넣는다.

코드 복사

(복사 붙여넣기할 코드)

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Gugi&display=swap" rel="stylesheet">
  • <link rel="preconnect" href="https://fonts.googleapis.com"> : 브라우저가 fonts.googleapis.com 서버에 미리 연결하도록 요청해서, 서버와의 DNS 조회 및 SSL 연결 시간을 줄여 font를 더 빨리 로드하도록 한다.
    • fonts.googleapis.com 서버는 폰트 설정(CSS 파일)을 제공하는 서버이다.
  • <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>: fonts.gstatic.com 서버에 미리 연결하고, crossorigin 속성을 설정한다. Font 파일을 빠르게 로드하면서 CORS 문제를 방지하는 역할이다.
    • fonts.gstatic.com 서버는 Google Fonts의 실제 font 파일을 제공하는 고속 서버이다.
    • Google은 전 세계에 분산된 서버(CDN - Content Delivery Network)를 사용해 font를 빠르게 제공한다. fonts.gstatic.com은 Google의 CDN에 연결된 서버로, 가까운 위치의 서버에서 font 파일을 다운로드받을 수 있도록 최적화된다.
    • Font 파일은 CORS를 통해 로드된다. 그래서 crossorigin 속성을 설정해 폰트 파일을 문제없이 가져오도록 해야 한다. Font 파일은 웹 브라우저의 보안 정책상 반드시 CORS 허용 설정이 되어야 다른 출처에서 사용할 수 있기 때문이다.
  • <link href="https://fonts.googleapis.com/css2?family=Gugi&display=swap" rel="stylesheet">: Google Fonts의 Gugi font(CSS 파일)를 불러온다.
    • 동작 과정
      •  HTML 파싱: 브라우저가 <link> 태그를 만나면 **href**에 지정된 URL인 https://fonts.googleapis.com/css2?family=Gugi&display=swap로 요청(Request)을 보낸다.
      • fonts.googleapis.com 서버는 요청된 폰트의 설정 정보를 담은 CSS 파일을 반환한다.
        • 이 CSS 파일에는 폰트 파일(실제 리소스)이 어디에 있는지 @font-face로 정의되어 있다. 
      • 브라우저는 CSS 파일을 확인한 후, 폰트 파일이 저장된 fonts.gstatic.com에 접근해 실제 폰트 파일(.ttf)을 다운로드한다.
      • 폰트 파일이 모두 로드되면, 지정된 텍스트에 폰트를 적용한다.
        • 이 과정에서 display=swap 옵션 덕분에 폰트 로딩 전에는 기본 폰트(fallback font)를 사용하다가, 폰트 로딩이 완료되면 화면에 적용된다.
      • (CSS 파일 예시)
@font-face {
  font-family: 'Gugi';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/gugi/v10/A2BVn5dXywshVKG1QnWJovb6aFU.ttf) format('truetype');
}

 


<style> 태그에 아래 예시와 같이 font-family를 설정한다.

html {
    font-family: "Gugi";
    font-weight: 400;
    font-style: normal;
}

 

Gugi를 적용한 HTML 예시

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Gugi&display=swap" rel="stylesheet">
</head>
<style>
    html {
        font-family: "Gugi";
        font-weight: 400;
        font-style: normal;
    }

    .normal {
        font-weight: normal;
    }

    .bold {
        font-weight: bold;
    }

    .custom {
        font-weight: 900;
    }
</style>

<body>
    <p>안녕하세요</p>
    <p class="normal">안녕하세요</p>
    <p class="bold">안녕하세요</p>
    <p class="custom">안녕하세요</p>
</body>

</html>

위 코드는 아래와 같이 화면을 렌더한다.

 

※ 참고: fonts.googleapis.com에서부터 로드된 CSS 파일의 @font-face의 역할

@font-face는 CSS 규칙 중 하나로, 웹페이지에서 custom font를 사용할 수 있게 해준다. 이 규칙을 사용하면 로컬 font가 아닌 외부 font를 가져와 웹페이지에 적용할 수 있다.

역할

  • Font 파일 선언:  웹페이지에서 사용할 font 파일을 지정한다. 다양한 형식(woff2, woff, ttf, eot 등)을 지원한다.
  • Custom font 이름 설정: font에 이름(font-family)을 부여해 나중에 CSS에서 해당 font를 사용할 수 있게 한다.
  • 다양한 font 스타일 정의: font 굵기(font-weight), 스타일(font-style), 문자 범위(unicode-rage, 선택 사항) 등을 지정할 수 있다.

기본 문법

@font-face {
    font-family: 'CustomFont'; /* 사용할 font의 이름 */
    src: url('CustomFont.woff2') format('woff2'),
         url('CustomFont.woff') format('woff'); /* font 파일 경로 및 형식 */
    font-weight: normal; /* font 굵기 */
    font-style: normal;  /* font 스타일 */
}

 

 

2. 직접 @font-face를 HTML <style> 태그에 정의해서 Custom Font를 쓰는 방법

@font-face 규칙을 직접 <style> 태그에 입력해서 사용하는 방법이다.

 

방법 1. 외부 서버에서 제공하는 font file을 사용할 수 있도록 @font-face를 직접 명시하기

 

눈누에서 제공하는 "쿠키런 글꼴" font를 사용해보자.

https://noonnu.cc/font_page/322

 

눈누

쿠키런 - 데브시스터즈(주)

noonnu.cc

 

우측의 "웹폰트로 사용"의 @font-face 코드를 복사한다.

 

복사한 코드를 아래처럼 HTML 파일에 붙여넣는다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        @font-face {
            font-family: "GmarketSansMedium";
            src: url("https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_2001@1.1/GmarketSansMedium.woff") format("woff");
            font-weight: normal;
            font-style: normal;
        }

        p {
            font-family: "GmarketSansMedium";
        }

        .normal {
            font-weight: normal;
        }

        .bold {
            font-weight: bold;
        }

        .custom {
            font-weight: 900;
        }
    </style>
</head>

<body>
    <p>안녕하세요</p>
    <p class="normal">안녕하세요</p>
    <p class="bold">안녕하세요</p>
    <p class="custom">안녕하세요</p>

</body>

</html>

font-family는 "GmarketSansMedium"로 정의되있고, p에 적용하였다.

위 코드는 아래와 같이 화면을 렌더한다.

 

 

방법 2. 로컬에 저장되있는 font 파일을 사용하도록 @font-face에서 직접 명시하기

로컬(웹 페이지의 디렉터리 기준)에 font 파일이 있다면, 이를 사용할 수 있다.

 

아래는 인터넷에서 "온글잎 박다현체" font 파일을 다운로드해서 로컬에서 사용한 예시이다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        @font-face {
            font-family: "Ownglyph_ParkDaHyun";
            src: url("./온글잎박다현체.ttf") format("woff");
            font-weight: normal;
            font-style: normal;
        }

        p {
            font-family: "Ownglyph_ParkDaHyun";
        }

        .normal {
            font-weight: normal;
        }

        .bold {
            font-weight: bold;
        }

        .custom {
            font-weight: 900;
        }
    </style>
</head>

<body>
    <p>안녕하세요</p>
    <p class="normal">안녕하세요</p>
    <p class="bold">안녕하세요</p>
    <p class="custom">안녕하세요</p>

</body>

</html>

위 코드는 아래와 같이 화면을 렌더한다.

 

 

요약

HTML 파일에서 CSS를 사용해 Font 스타일을 설정하는 방법을 아래와 같이 나눠서 알아보았다.

  1. Font 제공 서비스에서 제공하는 font 관련 정보(CSS 파일)를 먼저 확보한 다음, 해당 CSS 파일에 명시된 정보를 통해 외부 서버에 위치한 font 파일에 접근하기
  2. @font-face 직접 명시하기
    1. 외부 서버에서 제공하는 font file을 사용할 수 있도록 @font-face에 직접 명시하기
    2. 로컬에 저장되있는 font 파일을 사용하도록 @font-face에 직접 명시하기
반응형

'HTML&CSS' 카테고리의 다른 글

[HTML&CSS] CSS Box Model  (0) 2024.12.18
[HTML&CSS] HTML Boilerplate & HTML 기본 구조  (2) 2024.12.16
반응형

HTML Boilerplate

HTML Boilerplate란 HTML 문서를 생성하기 위한 기본 구조 또는 템플릿이다. HTML 문서를 적절히 포매팅하고 다양한 브라우저에서 작동하도록 해주는 필수 element와 tag들이 포함되어 있다.

HTML Boilerplate는 웹 개발 시작 초기에 사용되는 템플릿이다.

아래와 같은 boilerplate 코드를 모든 HTML 파일에 추가해야 한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

 

HTML 기본 구조

HTML의 기본 구조를 이해하기 위해, boilerplate에서 내용이 좀 더 추가된 아래 코드를 분석해보자.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="A brief description of the webpage.">
    <meta name="keywords" content="HTML, CSS, JavaScript, web development">
    <meta name="author" content="Your Name">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
    <link rel="preload" href="main.js" as="script">
    <script src="script.js" defer></script>
</head>
<body>
    <header>
        <h1>Welcome to My Website</h1>
    </header>
    
    <main>
        <p>This is a basic HTML boilerplate template.</p>
    </main>
    
    <footer>
        <p>&copy; 2024 Your Name</p>
    </footer>

    <script src="script.js"></script>
</body>
</html>

 

위 코드의 컴포넌트들을 하나씩 설명한다.:

  • <!DOCTYPE html>: HTML Living Standard 문서임을 명시한다. HTML Living Standard는 점진적으로 진화 중인, 현재 최신의 HTML 표준을 가라킨다.
  • <html>: HTML 문서의 루트(최상단 element)이며, 문서의 시작과 끝을 나타낸다.
    • lang="en" lang 속성은 HTML 문서의 주 언어를 선언한다. 이 경우엔 영어이며, 한국어로 지정하고 싶다면 "en" 대신 "ko"를 명시해야 한다.
  • <head>: 문서의 메타데이터를 정의하는 부분이다. 웹페이지의 설정, 정보, 스타일 및 스크립트 등을 포함한다.
    • <meta>: 웹페이지의 메타 정보를 담고 있다. 문서의 가장 윗부분에 적시되며, 웹페이지 자체에 디스플레이되지는 않지만, 웹페이지가 어떻게 동작할지, 인덱스될지, 스타일링될지 등의 핵심적인 정보를 제공한다.
      • <meta charset="UTF-8">: charset 속성은 캐릭터 인코딩을 UTF-8로 세팅한다. UTF-8로 하면 세계 각종 언어의 거의 대부분을 커버할 수 있다.
      • <meta name="viewport" content="width=device-width, initial-scale=1.0">: 이 웹페이지가 모바일 장치의 디스플레이에서도 정상적으로 표시되도록 하는 반응형 디자인을 갖추도록 제어한다.
      • <meta name="description" content="A brief description of the webpage.">: 검색엔진에 의해 검색되는 부분이며, 검색결과의 미리보기 텍스트(snippet)로 활용된다.
      • <meta name="keywords" content="HTML, CSS, JavaScript, web development">: 과거엔 중요했지만, 현대의 검색엔진에선 무시된다.
      • <meta name="author" content="Your Name">: 작성자 정보를 나타낸다.
      • <title>: 웹페이지의 제목을 나타낸다. 브라우저의 tab이나 검색엔진의 검색결과에 나타난다.
    • <link>: 외부리소스와 현재 HTML 문서를 연결하는 역할을 한다. 빈 태그와 속성만을 포함하고, <head> 안에만 위치할 수 있다. rel 속성은 대상 파일의 속성을 나타내며, href 속성은 연결 시 참조할 파일의 위치를 나타낸다.
      • <link rel="stylesheet" href="styles.css">: 스타일링을 위해 외부의 CSS 파일을 링크한다.
      • <link rel="icon" href="favicon.ico" type="image/x-icon">: 브라우저 탭에 표시될 작은 아이콘(파비콘)을 설정한다.
      • <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
        </head>: 외부 custom font를 로드한다.
      • <link rel="preload" href="main.js" as="script">: 리소스를 미리 로드하여 성능 최적화
      • <link rel="prefetch" href="future-page.html">: 리소스를 예비로 로드하여 성능 최적화
    • <script>: JavaScript 코드를 HTML 문서에 포함하거나 외부 JavaScript 파일을 연결함으로써, 웹 페이지의 동적 기능을 추가하는 데 사용된다. 
      • <head> 내에 <script>를 삽입하는 경우, 주로 문서 로딩 시 필요한 라이브러리나 설정 정보를 포함한다. 다만, <head>에 넣으면 페이지 로딩이 완료되기 전에 JavaScript가 실행되므로 페이지 로딩 성능에 영향을 줄 수 있다. 일반적으로 <body> 끝쪽에 넣는 것이 더 효율적이다.
      • <script src="script.js" defer></script>: 외부 Javascript 파일인 script.js을 연결한다. defer 속성은 HTML의 로딩이 끝난 뒤에 script를 동작시키도록 한다. defer가 아닌 async가 사용된 경우, JavaScript 파일을 비동기적으로 로드하여 페이지 렌더링에 영향을 미치지 않도록 한다.
  • <body>: 웹페이지의 본문을 나타내며, 실제로 사용자에게 보여지는 콘텐츠가 포함된다. 즉 페이지의 시각적인 부분 및 상호작용하는 요소들이 들어가는 영역이다. 웹페이지의 모든 내용은 <body> 안에 작성되어야 한다. 브라우저는 <body> 내부의 내용을 해석해서 렌더한다.
    • <header>: 웹페이지를 소개하는 내용 또는 navigational link를 담는다. 보통 웹사이트의 로고, 제목, 또는 메인 navigation 메뉴를 포함한다.
      • <h1>Welcome to My Website</h1>: 웹사이트의 title을 디스플레이 하고 있다.
    • <main>: 웹페이지의 주 콘텐츠(text, image 등)가 위치한다. 
      • <p>This is a basic HTML boilerplate template.</p>: 웹페이지를 묘사하는 단순한 문단이다.
    • <footer>: 웹페이지의 footer 콘텐츠(저작권, contact 정보, 링크 등)가 위치한다.
      • <p>&copy; 2024 Your Name</p>: 저작권 및 이름 정보가 담긴 문단이다.
    • <script>: 외부 JavaScript 파일을 연결하여 웹페이지의 동적 기능을 추가한다.
      • <head><script> 부분에서 말했듯이, <head> 안에 배치될 수 있지만, 성능 최적화를 위해 <body> 끝에 배치하는 것이 일반적이다. 또한  asyncdefer 속성을 사용하여 JavaScript 파일의 로딩 방식을 제어할 수 있다.
      • <script src="script.js"></script>: 외부 Javascript 파일인 script.js을 연결한다.

 

(브라우저 렌더 결과)

 

 

참고 링크)

https://www.freecodecamp.org/news/basic-html5-template-boilerplate-code-example/

 

Basic HTML5 Template: Use This HTML Boilerplate as a Starter for Any Web Dev Project

When you are building a new website, it is important to have a good starting foundation. In this article, I will explain what an HTML 5 boilerplate is and how to create a basic template to use in your projects. What is an HTML 5 boilerplate? Accordi...

www.freecodecamp.org

 

반응형

'HTML&CSS' 카테고리의 다른 글

[HTML&CSS] CSS Box Model  (0) 2024.12.18
[HTML&CSS] Font 설정하기  (0) 2024.12.17
반응형

https://www.acmicpc.net/problem/4613

 

파이썬에서 아스키 코드를 숫자로 변환하는 ord() 함수를 사용하면 알파벳을 매핑되는 숫자로 쉽게 변환할 수 있는 점을 이용했다.

그리고 문자열의 각 문자별 index를 쉽게 구하기 위해, enumerate()도 사용했다.

이번 문제부터 본격적으로 input()print()를 대신해서, 성능 개선을 위해 앞으로 쭉 sys.stdinsys.stdout 모듈 함수를 사용하려 한다.

(정답 코드)

import sys

lines = sys.stdin.read().splitlines()[:-1]

ans = []
for line in lines:
    sum = 0
    for i, c in enumerate(line, 1):
        if c != " ":
            sum += i * (ord(c) - ord("A") + 1)
    ans.append(str(sum))

sys.stdout.write("\n".join(ans))

반응형
반응형

https://www.acmicpc.net/problem/1620

 

처음에 문제를 읽었을 때는 단순히 리스트를 사용해서 쉽게 풀 수 있겠다 싶었다.

그래서 문제에서 주어지는 모든 input 정보를 하나의 리스트에 단순하게 append해버렸다.

그러나 이렇게 하면 무조건 시간 초과가 발생한다.

(시간 초과 발생 코드 1)

n, m = map(int, input().split())
pokemon = [""]
for _ in range(n):
    pokemon.append(input())
for _ in range(m):
    q = input()
    if q.isdigit():
        print(pokemon[int(q)])
    else:
        print(pokemon.index(q))

 

그래서 리스트가 아닌, 해싱이 적용된 딕셔너리를 사용하는 방법으로 수정했다. 

그러나 이번에도 (분명 내부적으로 시간 개선은 되었겠지만) 시간 초과가 발생했다.

(시간 초과 발생 코드 2)

n, m = map(int, input().split())
pokedex = {}
for i in range(1, n + 1):
    pokemon_name = input()
    pokedex[pokemon_name] = i
    pokedex[str(i)] = pokemon_name
for _ in range(m):
    q = input()
    print(pokedex[q])

 

여기까진 input을 받을 때 오직 input()만 사용한 naive한 코드이다.

나는 그동안 파이썬에서 문자열 input을 받을 때 사용하기 쉽다는 이유로 input() 함수를 써왔다.

그러나 이번 문제를 통해, 그랬다가는 시간 초과가 뜰 수 있는 문제가 있다는 것을 제대로 체감하게 되었다.

다른 블로그 글들을 참고하여, sys.stdinsys.stdout 모듈을 사용하는 방법을 택하였다.

(정답 코드)

import sys

n, m = map(int, sys.stdin.readline().split())
pokedex = {}
for i in range(1, n + 1):
    pokemon_name = sys.stdin.readline().rstrip()
    pokedex[pokemon_name] = str(i)
    pokedex[str(i)] = pokemon_name
for _ in range(m):
    q = sys.stdin.readline().rstrip()
    sys.stdout.write(pokedex[q] + "\n")

 

추가적으로 시도하진 않았지만, 더 최적화할 수 있는 여지가 충분히 있다는 것도 깨달았다.

현재 위 코드에서는 sys.stdin.readline()의 호출을 input을 한 줄 읽을 때마다 여러번 반복하고 있다. 그러나 문제에서 모든 input을 한번에 입력받을 수 있기 때문에, 굳이 한 줄씩 읽지 않아도 된다.

그리고 현재는 정답 출력도 한 줄씩만 수행하고 있다.

Input을 전부 단 한번의 read로 읽고, 정답을 단 한번의 write로 수행하면 성능이 아주 많이 개선될 것이다.

추후에 추가 최적화 작업을 해보겠다.

반응형

+ Recent posts