강사님 코드를 전체적으로 가져오기보다 내 코드와 비교하면서 배운 점을 정리해보려고 한다. 강의에서 들은 이야기도!
필자는 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;
}
<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
- 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을 공부할땐 알았던 태그들인데, 안쓰니 잊고있다 오랜만에 강사님 코드를 보고 아 이런게 있었지 하고 놀란 게 몇 가지 있다. 그리고 태그의 속성을 굉장히 꼼꼼하게 적은 것을 보고 좀 충격적이었다. 거기다 처음 보는 태그도 있었다...
<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>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>
필자는 카드의 주제를 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>
<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;
<em class="category" aria-hidden="true">Finance</em>
<strong class="title">title contents</strong>
<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>
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- 모든 트랜지션 프로퍼티를 한번에 지정
브라우저에 어떤 속성이 어떻게 변경될지 브라우저에 미리 알리는 역할을 한다. 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(-webkit-mask-image)
요소를 url에 지정된 이미지만큼만 보이게 처리한다.
.footer .instagram {
-webkit-mask-image: url(../img/icon_instagram.svg);
mask-image: url(../img/icon_instagram.svg);
}
이 점이 굉장히 혼란스러운 지점 중 하나였기때문에 자세히 살펴보았는데,
큰 블럭 위주로 클래스를 주고 그 클래스의 하위 요소는 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로 히든 처리를 하고 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>
반응형에 대응하기 위한 api가 굉장히 많더라. 터치스크린일 경우에 대해 대응한 내용을 볼 수 있었다.
터치스크린일 경우에는 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 통일
}
그 외 반응형 키워드
- 화면크기에 따른
@media screen and (min-width){}
@media screen and (max-width){}- 회전방향(화면방향)에 따른
@media only screen and (orientation: portrait){}
@media only screen and (orientation: landscape){}- 픽셀 밀도에 따른(4배수까지 대응하는 추세. dpi 3.5까지 나오고있다.)
@media only screen and (device-pixel-ratio: 2){}
@media only screen and (resolution: 144dpi){}- 화면비율
@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){}- 마우스포인터
@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){}- 프린트장치
@media only screen { background: rgb(230, 230, 230) } @media only print { background: white; @page { margin: 20em; }
- 컬러모드
@media all and (color) { } @media all and (monochrome) { } @media only screen and (prefers-color-scheme: dark) { } @media only screen and (prefers-color-scheme: light) { }
- 주변 광도
@media only screen and (light-level: normal) {} @media only screen and (light-level: dim) {} @media only screen and (light-level: washed) {}
- 애니메이션, 투명도
애니메이션이나 투명도를 기기에서 제어하는 경우가 있다. 이때는 아예 애니메이션이 동작하지 않도록 하는 것이 훨씬 낫다. 뚝뚝 끊기기 때문.@media only screen and (prefers-reduced-motion: reduce) {} @media only screen and (prefers-reduced-transparency: reduce) {}
- 그외
고대비 모드라는 것이 있다. 시각장애를 가진 분들을 위한 반응형 api.@media all and (prefers-contrast: more) {} @media all and (prefers-contrast: less) {}