[css] 반응형 웹 HTML 구조 잡기, 시멘틱 태그

KoEunseo·2023년 9월 16일
0

파헤쳐보자

목록 보기
31/31

강사님 코드를 전체적으로 가져오기보다 내 코드와 비교하면서 배운 점을 정리해보려고 한다. 강의에서 들은 이야기도!

1. wrapper

header/main/footer

필자는 div로 바디 바로 아래에 래퍼를 만들어 감싸주었다. 전체적으로 그리드를 줄 목적이었는데, 강사님 또한 래퍼로 감싼 것을 볼 수 있었다.
그리고 wrap<header<inner(div) 순으로 header 코드를 짰는데, inner를 굳이 준 이유는 뭘까 궁금했다. 보니까 모든 주요 태그(header, main, footer)의 하위 코드들을 inner로 감쌌다.
굳이 div가 없이도 header에 flex던 뭐던 주면 되지 않나? depth가 깊어지는 것을 최대한 피하고 싶은 건 누구든 마찬가지일 것 같기에 타당한 이유가 있을 것 같았다.
css 파일을 보니, 필자가 나름대로 한다고 적었지만 난리가 난 코드와 달리, 아주 정돈된 그야말로 문서를 볼 수 있었다.

.main_container > .inner,
.header > .inner,
.footer > .inner {
  margin: 0 auto;
}
.main_container > .inner {
  padding: 2rem;
  box-sizing: border-box;
}
.header > .inner,
.footer > .inner {
  display: flex;
}
.header > .inner {
  height: 100%;
  justify-content: space-between;
  align-items: center;
}

2. 아래는 필자의 header 코드이다.

<div class="wrapper">
      <!-- header -->
      <header class="header">
        <!-- header 내에 inner div를 하나 둔 이유가 뭘까? -->
        <div class="header_left">
          <h1 class="logo">
            <a>logo</a>
          </h1>
          <!-- button으로 넣음. -->
          <!-- <button><span>view manu</span></button> -->
          <!-- nav class 다시보기-->
          <nav>
            <ul class="nav header_nav">
              <li><a>TECHNOLOGY</a></li>
              <li><a>VIDEO</a></li>
              <li><a>IDEAS</a></li>
              <li><a>NEWS</a></li>
              <li><a>ENTERTAINMENT</a></li>
              <li><a>Finance</a></li>
              <li><a>LEADERSHIP</a></li>
            </ul>
          </nav>
        </div>
        <div class="hamburger">
          <img src="/src/assets/icons/MenuIcon.svg" />
        </div>
      </header>
  ...
<div>

우선 필자는 header를 두 분류로 나누었다.
[[logo [gnb]] hamburger-icon]
이런식으로, 왼쪽에 위치해야 할 컨텐츠와 오른쪽에 위치해야 할 컨텐츠를 나누어서 문서를 작성했다.
space-between을 주어서 왼쪽과 오른쪽 컨텐츠를 띄우기 위해서였다.

반면 강사님은 왼쪽 오른쪽으로 구간을 나누지 않았다.
inner 내에 로고, 메뉴버튼, gnb가 형제노드로 위치해있다.
그리고 space-between을 주셨는데, 이렇게 하면 로고와 gnb, 메뉴버튼의 레이아웃이 나란히 있게되지 않나? (아직 desktop 수업이 나가지 않아 확실히는 알 수 없다. 추후 추가할 예정.)

강사님의 의도를 나름대로 해석해보았다.

css 용도

  • .wrap: min-width를 지정하기 위함.
  • .inner: 가운데 정렬(공통), 메인 컨테이너에서 패딩과 보더박스를 주기 위함, 헤더와 푸터에 플렉스를 주기 위함

refactor

  1. div에 onClick 이벤트를 걸어서 버튼처럼 만들지 말것.
    용도에 맞게 a 태그나 button 태그를 써라.
<button type="button" class="btn_open_menu" id="viewMenu">
   <span class="hidden_txt">View menu</span>
</button>

버튼 태그 내에는 텍스트가 들어가야 한다. 그러나 스타일링 가이드 상 아이콘만 나타나야 하기 때문에 span으로 감싸서 버튼 이름을 준 후, hidden을 걸었다.


      <!-- footer -->
      <footer class="footer">
        <div class="footer_logo">
          <h1>
            <a>logo</a>
          </h1>
          <p>
            © 2018 Deck<br />
            Component based UI Kit
          </p>
        </div>
        <div class="footer_search">
          <!-- 여기서 form으로 감싸주고 fieldset, legend까지 -->
          <!-- <form action="" method="post">
            <fieldset>
              <legend>Subscribe</legend>
              <input
                type="email"
                required
                id="subscribeEmail"
                placeholder="Your E-mail"
                aria-label="Your E-mail"
              />
              <button type="submit">Subscribe</button>
            </fieldset>
          </form> -->
          <input type="email" placeholder="Your E-mail" />
          <button class="button">subscribe</button>
        </div>
        <!-- 여기서 connects로 위 input과 같이 그룹핑. 
        dl, dt, dd 사용.
        <dl>
              <dt>Follow us</dt>
              <dd>
                <a
                  href=""
                  target="_blank"
                  rel="noopener noreferrer"
                  class="instagram"
                  ><span class="hidden_txt">Instgram</span></a
                >
              </dd>
        -->
        <div class="footer_follow">
          <h2>Follow us:</h2>
          <ul class="footer_follow_list">
            <li>
              <a><img src="/src/assets/icons/instagram.svg" /></a>
            </li>
            <li>
              <a><img src="/src/assets/icons/pinterest.svg" /></a>
            </li>
            <li>
              <a><img src="/src/assets/icons/twitter.svg" /></a>
            </li>
            <li>
              <a><img src="/src/assets/icons/facebook.svg" /></a>
            </li>
          </ul>
        </div>
        <ul class="nav footer_nav">
          <li><a>TECHNOLOGY</a></li>
          <li><a>VIDEO</a></li>
          <li><a>IDEAS</a></li>
          <li><a>NEWS</a></li>
          <li><a>ENTERTAINMENT</a></li>
          <li><a>Finance</a></li>
          <li><a>LEADERSHIP</a></li>
        </ul>
      </footer>

구조

필자는 foorer<logo/search/follow/nav 이렇게 네가지 분류로 나누었다. 강사님은 이와 다르게 search와 follow를 합친 형태로 나누셨다.
footer<inner<copyright/sitemap/connects
footer 내부 구조를 카피라이트, 사이트맵, 커넥트로 나누었다.

그리고 필자는 푸터에도 로고를 h1으로 감쌌는데, 강사님은 푸터의 로고는 그냥 span으로 하셨더라. 생각해보면 그게 맞는 것 같기도 하고?
거기다 sitemap 순서가 필자와 다르게 중간에 두었는데, 푸터에 flex를 주고 order로 순서를 조정했다.

.footer .sitemap {
  order: 3;
  flex-wrap: wrap;
}
.footer .connects {
  order: 2;
  flex-direction: column;
  margin-bottom: 3.3rem;
}

이점은 내 생각에는 모바일 순서에 일단 맞춰서 작업하는 게 낫지 않을까 하는 생각이 들긴 한다. 최대한 연산이 일어나지 않도록 하는 게 좋다니까 할 수 있는 건 하는게 좋지 않겠나 싶어서.
사이트맵이 푸터의 마지막에 있던 중간에 있던 상관도 없을 것 같고 말이다. 의미론적으로 뭔가 있는걸까?

기억에서 꺼내 먼지쌓인 태그를 활용하자

처음 html을 공부할땐 알았던 태그들인데, 안쓰니 잊고있다 오랜만에 강사님 코드를 보고 아 이런게 있었지 하고 놀란 게 몇 가지 있다. 그리고 태그의 속성을 굉장히 꼼꼼하게 적은 것을 보고 좀 충격적이었다. 거기다 처음 보는 태그도 있었다...

fieldset, legend

  • fieldset: form의 여러 컨트롤과 레이블을 묶을 때 사용한다.
  • legend: 필드셋 콘텐츠의 설명(주제)
<form action="" method="post">
 <fieldset>
  <legend>Subscribe</legend>
  <input type="email" required id="subscribeEmail"     placeholder="Your E-mail" aria-label="Your E-mail" />
  <button type="submit">Subscribe</button>
 </fieldset>
</form>

dl, dt, dd: 데이터

  • dl: 설명 목록. dt, dd로 내용물을 표기한다. 주로 용어사전 구현, 키-값 쌍 목록을 표시할 때 사용한다.dt, dd가 꼭 1:1 관계여야 하는 것은 아니고, 1대 다, 다대 1도 가능하다.
  • dt: 용어.
  • dd: dt에 대한 설명.
<dl>
 <dt>Follow us</dt>
 <dd>
   <a href="" target="_blank" rel="noopener noreferrer" class="instagram"><span class="hidden_txt">Instgram</span></a>
  </dd>
  <dd>
   <a href="" target="_blank" rel="noopener noreferrer"
   class="pinterest"><span class="hidden_txt">Pinterest</span></a>
 </dd>
</dl>

main

card

em, area-hidden?

필자는 카드의 주제를 label로 표현했는데, 강사님은 em으로 강세를 주셨다.
그런데 거기에 aria-hidden을 주었는데, 이게 왜 들어가는걸까 궁금했다.
area-hidden이 참이면 화면에서 나오지 않게되는 줄 알았는데 화면에 표기가 되었기 때문이다. 내가 생각한 거랑 다른 걸까?(찾아보니 visibility: hidden이랑 헷깔렸던 것 같다.)
일단은 접근성 때문에, 탭(선택)되지 말라고 이와 같은 값을 준 것 같다.

mdn에서 말하는 area-hidden
다음을 숨김으로써 보조 기술 사용자의 경험을 향상할 수 있습니다.

  • 아이콘이나 이미지 등 순전히 장식적인 콘텐츠
  • 반복된 텍스트 등 중복된 내용
  • 메뉴와 같은 오프스크린 콘텐츠 또는 축소된 콘텐츠
    ... 시각적으로 아무것도 숨겨지지는 않습니다.
  • 경고:aria-hidden="true" 포커스 가능한 요소에는 사용하지 마세요.
    aria-hidden="true"아이콘을 보조 기술에 노출하면 중복이 발생하거나 아이콘에 표시되는 텍스트와 동일한 내용이 없으면 혼동이 발생할 수 있으므로 를 사용하여 보조 기술에서 아이콘을 숨깁니다.
<div class="card" style="background-image">
 <a href="">
   <em class="category" aria-hidden="true">Finance</em>
   <strong class="title">title</strong>
   <dl class="info" aria-hidden="true">...</dl>
 </a>
</div>

inline css: style

<div class="card" style="background-image: url(./img/card_bg_2.jpg)">

위와 같이 운영이슈로(이미지 교체를 js로 자주 할 가능성 매우 큼) 인라인으로 스타일링을 주신다고 한다.
이미지 태그를 쓰지 않고 백그라운드 이미지로 하는 이유는, 이미지로 레이아웃을 핸들링하기는 품이 좀 많이 들지만 몇줄만으로 컨트롤하기 아주 쉬워지기 때문이라고 하셨다.
그리고 그냥 예쁘게 보이기 위한 이미지일때는 bg, 그게 아니라 유저가 꼭 봐야 하는 이미지(상품 이미지)는 img 태그를 쓴다고 한다.

  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  margin-bottom: 2rem;
  min-height: 27.4rem;

잊고있던 html 태그들

<em class="category" aria-hidden="true">Finance</em>
<strong class="title">title contents</strong>
  • em: 강세 요소
  • strong: 중요
  • 또 dl
<dl class="info" aria-hidden="true">
  <dt class="share"><span class="hidden_txt">Share</span></dt>
  <dd>275</dd>
  <dt class="view"><span class="hidden_txt">View</span></dt>
  <dd>275</dd>
  <dt class="comment">
  <span class="hidden_txt">Comment</span>
  </dt>
  <dd>12</dd>
</dl>

눈여겨 볼 css 속성

transition-property?

poiemaweb

transition은 자동으로 발동되지 않는다.

hover와 같은 가상 클래스 선택자 혹은 자바스크립트의 액션에 의해 발동된다.
transition을 보통 한번에 지정해서 따로따로는 본 일이 많지는 않기에 이번기회에 정리해본다.

  • transition-property- 트랜지션의 대상이 되는 CSS 프로퍼티를 지정. 쉼표로 구분해 여러 속성을 지정하는것도 가능하다.
  • transition-duration- 트랜지션이 일어나는 duration을 s, ms 단위로 지정
  • transition-timing-function- 트랜지션 효과 속도의 리듬을 지정
    (디폴트로 ease 값을 가진다. linear, ease-in, ease-out, ease-in-out 등의 값이 있음.)
  • transition-delay- 트랜지션 발동 전 대기 시간 지정
  • transition- 모든 트랜지션 프로퍼티를 한번에 지정

will-change

브라우저에 어떤 속성이 어떻게 변경될지 브라우저에 미리 알리는 역할을 한다. transition 과 같은 동작의 경우 페이지 로딩에 지대한 영향을 끼치기 때문에, 위 키워드를 통해 최적화를 할 수 있게 된다.
너무 남발하면 안되고 적당히 써야 한다. 오히려 더 최적화에 악영향을 끼치게 될 수 있다.

.gnb {
  position: absolute;
  width: 100%;
  left: 0;
  top: 7.1rem;
  height: 0; /* 버튼 클릭시 height값이 생기게 됨 */
  overflow: hidden;
  background-color: var(--light-color);
  box-shadow: 0 0 0.5rem -0.5rem var(--dark-color);
  will-change: height, box-shadow;
  transition-property: height, box-shadow;
  transition-duration: 300ms;
  transition-timing-function: ease-out;
}
.gnb.open {
  box-shadow: 0 0.5rem 0.5rem -0.5rem var(--dark-color);
  height: 26.6rem;
}

mask-image, mask-repeat, mask-position, mask-size

mask-image(-webkit-mask-image)
요소를 url에 지정된 이미지만큼만 보이게 처리한다.

.footer .instagram {
  -webkit-mask-image: url(../img/icon_instagram.svg);
  mask-image: url(../img/icon_instagram.svg);
}

그 외

1. 어디까지 클래스를 부여할 것인가?

이 점이 굉장히 혼란스러운 지점 중 하나였기때문에 자세히 살펴보았는데,
큰 블럭 위주로 클래스를 주고 그 클래스의 하위 요소는 li, a와 같은 타입 선택자를 주로 사용하는 것처럼 보인다.

.gnb
.gnb.open
.gnb li
.gnb a

이렇게 하니까 스타일링이 어떤 요소에 들어간건지 정리되어 보인다.
자손 선택자, 가상선택자도 활용한다.

.card {}
.inner > .card:last-child {}
.card > a {}
.card > a:hover,
.card > a:focus {}
.card > a:hover .title,
.card > a:focus .title {}
.card .info dd:not(:last-child) {}

선택자만 봐도 스토리가 그려지는 느낌? 너무 길어지지 않게 최대한 두개 이상의 선택자를 나열하지는 않는 것 같다.

  • 선택자를 너무 많이 쓰면 css에서 그 선택자를 다 탐색해야하기때문에 느려질 수 있다고 한다.

요소에 대한 설명을 잊지 말것.

화면에 텍스트가 나타나면 안되더라도, css로 히든 처리를 하고 html 문서에는 꼭 표기를 한다.

예시 1
<dl>
  <dt>Follow us</dt>
  <dd>
    <a
       href=""
       target="_blank"
       rel="noopener noreferrer"
       class="instagram"
       ><span class="hidden_txt">Instgram</span></a
      >
  </dd>
</dl>
예시 2
<dl class="info" aria-hidden="true">
  <dt class="share"><span class="hidden_txt">Share</span></dt>
  <dd>275</dd>
  <dt class="view"><span class="hidden_txt">View</span></dt>
  <dd>275</dd>
  <dt class="comment"><span class="hidden_txt">Comment</span></dt>
  <dd>12</dd>
</dl>

2. 반응형

반응형에 대응하기 위한 api가 굉장히 많더라. 터치스크린일 경우에 대해 대응한 내용을 볼 수 있었다.

@media all and (pointer: coarse)

터치스크린일 경우에는 hover, focus가 동작할 일이 없기 때문에 주로 그 부분을 건들인 것 같아 보인다.

@media all and (pointer: coarse) and (hover: none) {
  a:hover,
  a:focus {
    text-decoration: none;
  }
  .card > a:hover .title,
  .card > a:focus .title {
    text-decoration: none;
  }
  .leading .link:hover,
  .leading .link:focus { color, background-color }
  .footer .connects a:hover,
  .footer .connects a:focus { background-color }
  .gnb a,
  .gnb a:hover,
  .gnb a:focus { color } color 통일
}

그 외 반응형 키워드

  1. 화면크기에 따른
    @media screen and (min-width){}
    @media screen and (max-width){}
  2. 회전방향(화면방향)에 따른
    @media only screen and (orientation: portrait){}
    @media only screen and (orientation: landscape){}
  3. 픽셀 밀도에 따른(4배수까지 대응하는 추세. dpi 3.5까지 나오고있다.)
    @media only screen and (device-pixel-ratio: 2){}
    @media only screen and (resolution: 144dpi){}
  4. 화면비율
    @media only screen and (aspect-ratio: 2/3){}
    @media only screen and (aspect-ratio: 6/16){}
    @media only screen and (aspect-ratio: 9/19.5){}
  5. 마우스포인터
    @media only screen and (pointer: coarse) and (any-pointer: fine){}
    @media only screen and (pointer: fine) and (any-pointer: course){}
    @media only screen and (hover: none) and (any-hover: hover){}
  6. 프린트장치
@media only screen { background: rgb(230, 230, 230) }
@media only print { 
	background: white;
	@page {
    	margin: 20em;
    }
  1. 컬러모드
@media all and (color) { }
@media all and (monochrome) { }
@media only screen and (prefers-color-scheme: dark) { }
@media only screen and (prefers-color-scheme: light) { }
  1. 주변 광도
@media only screen and (light-level: normal) {}
@media only screen and (light-level: dim) {}
@media only screen and (light-level: washed) {}
  1. 애니메이션, 투명도
    애니메이션이나 투명도를 기기에서 제어하는 경우가 있다. 이때는 아예 애니메이션이 동작하지 않도록 하는 것이 훨씬 낫다. 뚝뚝 끊기기 때문.
@media only screen and (prefers-reduced-motion: reduce) {}
@media only screen and (prefers-reduced-transparency: reduce) {}
  1. 그외
    고대비 모드라는 것이 있다. 시각장애를 가진 분들을 위한 반응형 api.
@media all and (prefers-contrast: more) {}
@media all and (prefers-contrast: less) {}

3. css 팁

  • 기본 폰트 사이즈가 16px일때는 %나 rem을 예측하기 힘들다.
    font-size를 10px로 하면 예측이 쉽다.
    이때 10px 말고 62.5%로 한다.
  • var(): 변수설정. 보통 root에서 컬러를 변수로 설정한다.
  • calc(): 계산. 100%에서 마진을 빼는 형태로 많이 사용한다.
  • min()/max()
  • clamp(): min + max, 적용한 것 중
  • env() : 노치있는 스마트폰에서 설정
profile
주니어 플러터 개발자의 고군분투기

0개의 댓글