지난 시간 로고를 위치시키고 안내링크 모음까지 했으니 header의 나머지 영역인 메인 메뉴와 그 밑의 하위 메뉴를 작업해본다.
- 지난 시간 작업한 상황에서 로고는 position이 absolute가 되면서 떠올랐기 때문에 별도의 height 값이 없어진 상위요소 header은 높이가 안내링크 영역만큼으로 줄어들었다.
- 이를 해결하기 위해 nav를 만듦으로써 header를 적절한 크기로 늘리자.
- 시안의 메뉴 바 (HTML에 대해, CSS에 대해, ..., 자료실) 부분을 클릭하면, 링크로 이동하는 것이 아니라 하위 항목만 보이게끔 만들어주자. (현재 hover만 해도 하위 항목이 보이는 시안과는 다르게 해보기)
- 하위 항목을 지정해주기 위해
<nav class="navigation">
안에<ul class="menu">
을 두어 묶어주고, 각 메뉴는<li class="menu-item">
속 링크<a class="menu-item-button">
태그로 한다.- ul의 자식요소는 li만 올수가 있기 때문에 반드시 li 안에 다른 태그가 오는 순서로!
- 메인 바의 메뉴에 어떤 태그를 쓸지 고민해보자.
- span을 쓰면 클릭 이벤트를 발생시킬 수가 없다.
- button을 쓰면 클릭은 가능하지만 border-box를 비롯하여 default로 주어지는 다양한 속성을 재정의해야 하며 같은 맥락에서 cross-browser 시의 customizing이 까다롭다.
- 그렇다면 a 태그로 하되 button의 역할을 하도록 ARIA를 사용하는 방법이 있다. a태그에
role="button"
을 넣어주고,href="#" class="menu-item-button"
으로 지정
- 하위 항목들은 별도의 스타일로 꾸며줘야 하므로 li 속
<ul class="sub-menu"
로 묶어준다.
- import는 무조건 첫 줄에 써야 컴퓨터 읽기 순서(위->아래)상 문제가 없다.
normalize.css
가져오기- style.css의 첫 줄에
@import url(./normalize.css);
- index.html에 style.css 링크하듯
<link rel="normalize" href="css/normalize.css">
: 이 방법은 파일 여러개일 때 관리가 귀찮아지니까, 개발용에는 css source 파일 여러개를 따로 import하여 관리하되, 배포(distribution file)용에는 하나의 파일을 만들어 html에 하나만 링크한다. (source files를 모두 합치고 줄바꿈도 없게 uglify한 하나의 css파일 main.css로) - Sass라는 CSS 전처리기는 위와 같이 각 모듈별로 쪼개놓고 하나로 만들어주는 것까지 다 해주는 기능을 가진다.
- style.css의 첫 줄에
- 웹폰트 가져오기
- 폰트를 웹에서 가져오면 브라우저마다 해당 글꼴이 달라질 염려가 없다.
- 구글과 어도비의 합작인 Spoqa Han Sans를 데려오자.
- 구글링한 깃헙 소스코드
@import url(//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSansNeo.css);
- 잘 import되었나 확인하려면 적용된 페이지에 가서
개발자도구-Network-Font
- markup 상에는 존재하되 화면에는 나오지 않아야하는 부분이 있다. 일반인은 맥락을 통해 유추할 수 있고 디자인 상 보이지 않지만 시각장애인을 위한 스크린리더에는 읽혀야하는 부분 등이다.
- 이런 부분들에 class명을 a11y-hidden 등으로 준 후 숨김콘텐츠로 처리하여 접근성을 확보할 수 있다.
- (Wrong)
.a11y-hidden{display: none;}
: 기껏 숨김콘텐츠 만들어놓고 접근성을 아예 없애버리는 짓 - (Old way)
.a11y-hidden{position: absolute; top:-9999px;}
: 일명 안드로메다로 보내버리기 전략이지만 이렇게 할 경우 이 부분을 screen reader가 위치를 잡기 위해 top좌표를 찾아가면서 갑자기 스크롤바가 생기는 일이 발생 - (New better way) 스크롤바가 튀지 않도록 제자리에 있으면서도 보이지는 않게 하는 방법이 있다.
.a11y-hidden{width: 1px; height: 1px; margin: -1px; overflow: hidden;}
으로 하면 제자리에 존재하긴 하면서 보이지 않는다.- 이렇게 할 때 몇몇 경우엔 점이 생기는데 그 점까지 없애주려면 clip-path 속성을 이용한다.
clip-path: polygon(0 0, 0 0, 0 0);
을 주면 영역이 전혀 보이지 않는다.- clip-path는 IE 하위버전에서는 안 되기 때문에 IE하위버전에서는
clip: rect(0 0 0 0)
로 해줘야 하지만 잘 안 쓰이는 속성이라 권장은 X
- clip-path는 IE 하위버전에서는 안 되기 때문에 IE하위버전에서는
- menu로 네이밍한
<nav>
속 ul에 메뉴바 스타일 입히기.
- ul 스타일 초기화: agent(browser)의 default값으로 주어진 margin, padding, list-style을 0과 none으로 제거해준다.
- 앞으로 나올 ul, ol 스타일도 동일하게 작업해주려면 아예 mark-up 상 태그에 class이름에 reset-list를 추가해서 초기화해준다.
/* 스타일 초기화 */
.reset-list{
list-style-type: none;
padding-left: 0;
margin: 0;
}
element(ul)에 스타일을 주기보다는 이처럼 class(.reset-list)에 스타일을 주어야 추후에 있을 변경에 대해서 유연하게 대응할 수 있다.
- 배경색 입히기:
background: linear-gradient(to bottom, 시작색깔 0%, 중간색깔 00%, ..., 끝색깔 100%);
- CSS3 gradient generator 가서 그라데이션 설정 후 코드값을 복사
- 개발단계에서는 표준코드만 복붙하더라도 나중에 cross-browser을 어디까지 할 건지에 따라서 prefix가 달라진다는 점을 유념하여 필요한 코드를 복붙
- 위와 같은 고민을 하지 않아도 되게끔 Post CSS가 prefix를 알아서 붙여주기도 한다.
- 우리는 그냥 표준코드만 넣어주되 호환 안되는 브라우저를 위해 해당 배경그라디언트가 뜨지 않을 경우 나올 background 색깔을 fall-back으로 넣어줄 것(콤마 없이 앞에 넣어주면 된다)
- 메뉴바 위에 검은색 선 입히기
border-top: 2px solid #000;
상자 크기에 영향 주니까 고려하며 사이즈 조정 필요box-shadow: 0 -2px 0 0 #000;
로 주는 방법도 있지만 우리는 위의 방법으로 하고 상자 크기를 2px 더해주자.
- header 기준으로 위는 안내링크모음 다음으로 위치하고 좌우와 아래는 떨어지게끔
header{padding: 0 30px 35px;}
- 둥근모서리가 아래쪽에만 들어가므로
border-radius: 0 0 5px 5px;
- border-radius의 값은 공백으로 구분하며 순서는 left-top부터 시계방향
/
를 통해 x축과 y축의 값 지정도 가능 (e.g.border-radius: 0 0 30px 30px / 0 0 5px 5px
)
- 메뉴 바 및 활성화된 메뉴 항목 꾸미기
- 상위 메뉴는 float로, 하위 메뉴는 inline-block으로 쌓아주자
- 상위 메뉴인 menu-item을
float:left
- menu-item들이 하위메뉴의 너비만큼 서로 떨어져 있어서 원하는 결과(서로서로 옆에 붙은 모양)가 나오지 않는다. 이럴 때 하위 메뉴인 ul submenu에 position:absolute를 줌으로써 하위메뉴의 width가 아예 인식되지 않게 한다.
- 부모요소인 menu는 높이를 잃어버리므로 overflow를 쓰거나 가상요소
::after
로 clear를 해줘야 한다. 하지만 overflow:hidden을 할 경우 하위메뉴도 숨겨진다는 단점도 있고 하니 이번에는 더이상 추가될 메뉴가 없다고 가정하고 menu에 직접 높이를 준다. - 아까 border-top 줬던 것을 감안하여 45px height를 주려면 47px로 줘야 한다.
- menu-item이 로고부분 이후 위치하게 하기 위해 menu에 padding-left를 주거나 menu-item에 margin-left를 준다.
- 그러나 후자의 경우 줄바꿈시 로고영역을 침범하니까 안전한 전자를 선택
- 왼쪽에 하얀 경계선을 넣어주기 위해
border-left: 1px solid #fff;
- menu-item들의 안쪽 여백을 주되, 링크영역이 넓어여 클릭하기 쉬우니까 menu-item의 a태그 클래스인 menu-item-button를 block으로 만든 후 padding 주되 아까 menu에 border-top들어가있으니 top에 2px 주고 좌우는 20px로
padding: 2px 20px 0;
- 위와 동일한 선택자에 글자 테두리 효과
text-shadow: 1px 1px 0 #000, -1px -1px 0 #000;
- line-height를 이젠 45px로 하여 메뉴 높이와 같도록.
- 이제 하위 항목 중 클릭된 항목인
menu-act
로 지정된 부분을 꾸며준다.- 그냥 menu-act만 선택하면 그 하위 요소는 자기의 값을 그대로 가져간다. 더 구체적으로 menu-act 속 menu-item-button까지 선택해주자.
color: yellow;
로 글자색을 바꿔준다- 밑줄을 넣기 위해 border-bottom을 하면 padding 부분인 전체 메뉴에 밑줄이 들어가지만 우리가 원하는 건 글자부분에만 밑줄이 들어가는 것이므로
.menu-item-button::after
을 만들어준 후content:""
로 존재하게 하고, 옆에 붙어 정렬되지 않도록display:block
을 해준 후background-color: #000
을 주고 height를 2px로 준 후margin-top: -2px
로 끌어올려 menu-item-button의 높이 47px에다가 padding-top으로 2px 오버된 아래부분에 겹쳐지게 한다. border-bottom으로 줄 수도 있지만 이렇게 하면 shadow를 줄 수도 있고 하니...(이부분이 약간 tricky...)
- 하위메뉴(sub-menu) 스타일링
- 상위메뉴의 line-height가 상속되지 않게 하려면 menu-item이 아닌 menu-item-button에 주는 것이 좋다. 안 그러면 하위 메뉴도 간격이 위아래로 널찍.
- 아까 상위메뉴의 너비에 영향을 주지 않기 위해 하위메뉴의 position을 absolute로 주었고, offset parent 요소는 header인 상태
- header에게 다른 작업을 할 경우 영향을 받을 수도 있으니, 이왕이면 더 가까운 부모요소에게 주는 것이 안전
- 각 하위메뉴의 상위메뉴인 li(menu-item)를 offset parent로 설정해주기 위해
.menu-item{position: relative;}
를 넣어준다. - 메뉴바에서 밑으로 47px 떨어져있어야 하므로
top: 47px
- 첫 3개의 sub-menu는 상위메뉴의 좌측을 기준으로, 나머지 3개는 상위메뉴의 우측을 기준으로 배치한다.
.sub-menu1, .sub-menu2, .sub-menu3 {left:0;} .sub-menu4, .sub-menu5, .sub-menu6 {right:0;}
- 하위메뉴를 가로로 흘러가게끔 하기 위해
.sub-menu li {display: inline-block;}
- 그러나 이 경우 sub-menu가 부모요소 크기만큼만 좌우로 흘러가므로 밑으로 내려간다. 이를 방지하기 위해 따로 sub-menu에 width를 줘도 되지만
white-space: nowrap
로 간단하게 줄바꿈 금지를 선언할 수 있다.
- 그러나 이 경우 sub-menu가 부모요소 크기만큼만 좌우로 흘러가므로 밑으로 내려간다. 이를 방지하기 위해 따로 sub-menu에 width를 줘도 되지만
- 하위메뉴의 bullet point를 따로 만들어 넣어주기 위해서는 font awesome이나 fontello 등의 서비스를 이용할 수 있다.
- 우리는 준비된 fontello.css를 import하고 하위메뉴의 a 태그에 해당 클래스 이름을 넣으면 알아서 ::before 요소를 만들어 아이콘이 자리잡는다.
- a태그에도 위아래로 여백을 넣어 링크 클릭을 조금 더 용이하게끔 넓혀주기 위해 inline-block화 시킨다. 좌우 패딩은 0으로 하고 margin-right도 넣어서 각 링크마다 구분되게끔, 그리고 마우스를 갖다대거나 포커스를 받았을 때 글자 색이 빨갛게 되도록 처리한다.
.sub-menu a{
display: inline-block;
padding: 10px 0 8px;
margin-right: 5px;
}
.sub-menu a:hover, .sub-menu a:focus{
color: #f00;
}
- 비주얼 영역의 높이는 앞으로도 변하지 않는다는 전제 하에 120px로.
- 배경그림 위의 글자는 mark-up에 추가하여 애니메이션을 줘보자.
- div로 넣고 클래스를 visual-text로.
- 글자 내용 중
&
와 같은 기호는 경우에 따라 반드시 변환해야하는 특수문자일 때도 있으니 안전하게&
로 입력해준다. 그 외의 특수문자들은 html entities로 찾아보면 나오며 업데이트는 잘 안되지만 W3C schools에서도 확인 가능, 특히 화폐기호는 복붙하지말고 이런 entity 값으로 넣어주는 게 좋다.
- 배경그림은 background에서 넣어 처리해보자. CSS의 multi-background 기능을 활용해볼 것.
- 이름지정: 텍스트 파트니까 textAni로.
- 액션 정의: 글자의 이동, 투명도 변화, 글자크기 변화를 볼 수 있다.
- 글자는 좌상단(0, 0)에서 우하단(top 75px, left 400px)로 이동
position: absolute;
: offset parent를 선택해주어야 하므로 visual의 position을 relative로 주는 작업 필수.- 글자의 margin값이나 div의 padding 값을 점점 늘려주는 방식: 글자에 margin을 주면 텍스트를 포함한 visual 영역 자체가 margin값을 가지므로 padding으로 줘야 함
transform: translate (x좌표, y좌표);
: 좌우로 긴 블록 크기 그대로 이동하기 때문에 이동 후 스크롤바가 생긴다. 이를 방지하기 위해 visual text를 inline-block으로 처리해주거나 width 값을 임의로 지정해줘야.- 위 세가지 모두 같은 효과를 주지만 reflow를 발생시키며 성능 문제를 일으킨다. 특히 position을 바꾸는 것은 움직일 때마다 매번 다시 그리기 때문에 GPU를 완전 많이 차지한다. 가장 성능면에서 효율적인 transform을 사용하도록 하자.
font-size
를 점점 키워준다- 투명도에 변화를 준다.
- opacity로 주면 상자 전체의 투명도가 조절된다.
- 텍스트 투명도만 조절하려면
color: rgba(0 0 0 0)
로 alpha값을 준다.
- CSS에 애니메이션 정의
@keyframes textAni{
0% { #처음 시작할 때의 값을 다 넣어준다. 0% 대신 from으로 넣어도 되지만 form과 헷갈리니까 0%으로.
font-size: 12px;
color: rgba(0, 0, 0, 0);
transform: translate (0, 0);
}
100% {
font-size: 24px;
color: rgba(0, 0, 0, 1);
transform: translate (400px, 75px);
}
}
이제 이렇게 정의해준 애니메이션을 받을 선택자를 연결해주되, 두가지를 꼭 넣어주어야 애니메이션이 동작한다.
.visual-text {animation-name: textAni; animation-duration: 2000ms;}
- 이렇게만 하면 애니메이션이 100%에 도달한 이후 다시 0%의 값으로 끝나는데, 100%로 지정한 상태로 머물게 하려면
animation-fill-mode: forwards;
를 넣어주어야 한다. - 글씨체도 바꿔준다.
.visual-text {
animation-name: textAni;
animation-duration: 2000ms;
animation-fill-mode: forwards;
font-family: Georgia, font1, font2 #Geargia가 지원되지 않는 경우 등장할 다른 폰트들
}
- 이름지정: background에 이미지를 넣어 애니메이션을 줄 거니까 bgAni로.
- 액션 정의: 꽃들이 번갈아가며 등장 및 사라진다. 시간차를 두어 투명도 주기.
- CSS에서 작업해주기.
- 두개의 꽃세트를 만들기 위해 두 가상요소선택자를 부모영역 크기만큼 겹쳐만들고 그 안에 background image를 absolute로 position으로 주도록 하자.
- markup으로 새로운 빈 div를 주는 방법도 있지만 multi-background를 활용해보자
- before에 꽃 두개, after에 꽃 두개를 각각 콤마로 넣어준다. multi-background에서는 콤마로 하면 영원히 추가 가능
.visual::before {background: url(이미지1주소) no-repeat x축값 y축값, url(이미지2주소) no-repeat x축값 y축값;}
- 위 방법과 결과는 같지만 no-repeat 등 중복되는 부분의 효율화를 위해 visual에
background: no-repeat;
넣어주고.visual::before {background-image: url(이미지1 주소), url(이미지2주소); background-position: 이미지1 좌표값, 이미지2 좌표값;}
로 넣어준다.
- 애니메이션은 투명도만 조절해주면 되는 문제이므로
opacity: 0 (0%) 또는 1 (100%);
로. - 꽃이 사라졌다가 다시 나타나는 애니메이션의 반복
- 계속해서 애니메이션이 동작하도록
animation-iteration-count: infinite;
@keyframes bgAni
에 0%, 50%, 100%로 줄 수도 있지만animation-direction: alternate;
으로 하면 알아서 방향이 앞뒤로 오간다.
- 계속해서 애니메이션이 동작하도록
@keyframes bgAni{
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
.visual::before, .visual::after{
content: "";
position: absolute; #부모 영역인 .visual에도 position:relative 해서 offset parent로 만들어줄 것
top: 0;
left: 0;
width: 100%;
height: 100%; #부모영역과 동일
background: no-repeat;
animation-name: bgAni;
animation-duration: 2000ms;
animation-iteratio-count: infinite;
animation-direction: alternate;
}
- 꽃이 시간차를 두고 등장해야하기 때문에 .visual::after의 animation은 딜레이값을 준다.
.visual::before{
background-image: url(이미지1주소), url(이미지2주소);
background-position: 이미지1 좌표, 이미지2 좌표;
}
.visual::after{
background-image: url(이미지3주소), url(이미지4주소);
background-position: 이미지3 좌표, 이미지4 좌표;
animation-delay: 1000ms;
}
- 숨김콘텐츠나 reset-list처럼 간단하게 처리하는 방법들을 고안해낸 사람은 누굴까. 정말 대단하다...
- CSS에서 효과적으로 애니메이션을 표현할 수 있다니 신기하다.