애니메이션(Animation) 효과는 HTML 요소에 적용되는 CSS 스타일을 다른 CSS 스타일로 부드럽게 변화시킨다. 애니메이션은 애니메이션을 나타내는 CSS 스타일과 애니메이션의 sequence 를 나타내는 복수의 키프레임(@keyframes)들로 이루어진다.
transition으로도 어느 정도의 애니메이션 효과를 표현할 수 있으나 animation 보다는 제한적이다. 일반적으로 트랜지션 효과는 요소 속성값이 다른 값으로 변화할 때 주로 사용하며 요소의 로드와 함께 자동으로 발동되지 않는다. :hover 와 같은 가장 클래스 선택자(Pesudo-Class Selector) 또는 자바스크립트의 이벤트와 같은 부수적 액션에 의해 발동된다.
즉 transition 속성은 단순히 요소의 속성 변화에 주안점이 있다면 animation 속성은 하나의 줄거리를 구성하여 줄거리 내에서 세부 움직임을 시간 흐름 단위로 제어할 수 있고 전체 줄거리의 재생과 정지, 반복까지 제어할 수 있다.
일반적으로 CSS 애니메이션을 사용하면 기존의 JavaScript 기반 애니메이션 실행과 비교하여 더 나은 렌더링 성능을 제공한다고 알려져 있다. 그러나 경우에 따라서는 JavaScript를 사용하는 것이 나을 수도 있다. jQuery 등의 애니메이션 기능은 CSS보다 간편하게 애니메이션 효과를 가능케한다.
가장 중요한 것은 브라우저에서 애니메이션 효과가 부드럽게 실행되는 것이다. 그리고 애니메이션 효과 작성에 소요되는 시간과 수고이다. 여러 사항들을 고려하여 자바스크립트를 사용하여야 할지 CSS를 사용하여야 할지 결정하여야 한다.
속성 | 설명 | 기본값 |
---|---|---|
animation-name | @keyframes 애니메이션 이름을 지정한다 | |
animation-duration | 한 싸이클의 애니메이션에 소요되는 시간을 초 단위(s) 또는 밀리 초 단위(ms)로 지정한다 | 0s |
animation-timi-function | 애니메이션 효과를 위한 타이밍 함수를 지정한다. | ease |
animation-delay | 요소가 로드된 시점과 애니메이션이 실제로 시작하는 사이에 대기하는 시간을 초 단위(s) 또는 밀리 초 단위(ms)로 지정한다. | 0s |
animation-iteration-count | 애니메이션 재생 횟수를 지정한다. | 1 |
animation-direction | 애니메이션이 종료된 이후 반복될 때 진행하는 방향을 지정한다. | normal |
animation-fill-mode | 애니메이션 미실행 시(종료 또는 대기)요소의 스타일을 지정한다. | |
animation-play-state | 애니메이션 재생 상태(재생 또는 중지)를 지정한다. | running |
animation | 모든 애니메이션 속성을 한번에 지정한다. |
CSS 애니메이션과 트랜지션 방식의 주된 차이는 @keyframes rule에 있다. 이 rule을 사용하면 애니메이션의 흐름(sequence) 중의 여러 시점(breakpoint)에서 CSS 속성값을 지정할 수 있다.
<!DOCTYPE html>
<html>
<head>
<style>
div {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
animation-name: move;
animation-duration: 5s;
animation-iteration-count: infinite;
}
/* @keyframes rule */
@keyframes move {
/* keyframe */
from {
left: 0;
}
/* keyframe */
to {
left: 300px;
}
}
</style>
</head>
<body>
<div></div>
</body>
</html>
@keyframes rule은 시간의 흐름에 따라 애니메이션을 정의한다. 여러 개의 키프레임을 정의하거나 애니메이션 중에서 특정 CSS 속성에 값을 지정하는 지점을 정의할 수 있다.
위 코드에서 @keyframes 뒤에 애니메이션을 대표하는 이름을 부여하였다.
@keyframes move { }
from, to 키워드를 사용하여 애니메이션의 시작과 끝 시점을 정의하였다. 그리고 애니메이션의 시작 시점을 의미하는 from 키프레임 내에서는 left 속성값에 0을, 애니메이션의 끝 시점을 의미하는 to 키프레임 내에서 left 속성값에 300px을 지정하였다. 그 결과, 정지 상태에서 오른쪽에서 300px 이동하는 애니메이션이 실행된다.
@keyframes move {
/* 애니메이션 시작 시점 */
from { left: 0; }
/* 애니메이션 종료 시점 */
to { left: 300px; }
}
from, to 키워드 대신 %를 사용할 수 있다. 또한 시작과 끝 키프레임 사이에 %단위로 키프레임을 삽입할 수 있다.
@keyframes move {
0% { left: 0; }
50% { left: 100px; }
100% { left: 300px; }
}
위 코드에서 @keyframes 뒤에 애니메이션을 대표하는 임의의 이름을 부여하였다.
@keyframes move{}
이 이름을 animatio-name 속성값으로 지정하여 사용하고자 하는 @keyframe rule을 선택한다. 하나 이상의 애니메이션 이름을 지정할 수 있다.
<!DOCTYPE html>
<html>
<head>
<style>
div {
position: absolute;
width: 100px;
height: 100px;
animation-name: move, fadeOut, changeColor;
animation-duration: 5s;
animation-iteration-count: infinite;
}
@keyframes move {
from { left: 0; }
to { left: 300px; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes changeColor {
from { background-color: red; }
to { background-color: blue; }
}
</style>
</head>
<body>
<div></div>
</body>
</html>
한 싸이클의 애니메이션에 소요되는 시간을 초 단위(s) 또는 밀리 초 단위(ms)로 지정한다.
animation-duration: .5s;
animation-duration: 500ms;
animation-duration은 반드시 지정해야 한다. 지정하지 않은 경우 기본값 0s가 설정되어 어떠한 애니메이션도 실행되지 않는다.
애니메이션 효과를 위한 수치 함수를 지정한다.
요소가 로드된 시점과 애니메이션이 실제로 시작하는 사이에 대기하는 시간을 초 단위(s) 또는 밀리 초 단위(ms)로 지정한다.
animation-delay: 2s;
애니메이션 주기의 재생 횟수를 지정한다. 기본값은 1이며 infinite로 무한 반복이 가능하다.
animation-iteration-count: 3;
애니메이션이 종료된 이후 반복될 때 진행하는 방향을 지정한다.
속성값 | 설명 |
---|---|
normal | 기본값으로 from(0%)에서 to(100%) 방향으로 진행한다. |
reverse | to 에서 from 방향으로 진행한다. |
alternate | 홀수번째는 normal로 , 짝수번째는 reverse로 진행한다. |
alternate-reverse | 홀수번째는 reverse로, 짝수번째는 normal로 진행한다. |
<!DOCTYPE html>
<html>
<head>
<style>
div {
width: 100px;
height: 100px;
background: red;
position: relative;
animation: myAnimation 5s infinite;
/*홀수번째는 normal로, 짝수번째는 reverse로 진행*/
animation-direction: alternate;
}
@keyframes myAnimation {
0% { background: red; left: 0px; top: 0px; }
25% { background: yellow; left: 200px; top: 0px; }
50% { background: blue; left: 200px; top: 200px; }
75% { background: green; left: 0px; top: 200px; }
100% { background: red; left: 0px; top: 0px; }
}
</style>
</head>
<body>
<div></div>
</body>
</html>
애니메이션 미실행 시(대기 또는 종료)요소의 스타일을 지정한다.
속성값 | 상태 | 설명 |
---|---|---|
none | 대기 | 시작 프레임(from)에서 설정한 스타일을 적용하지 않고 대기한다. |
- | 종료 | 애니메이션 실행 전 상태로 애니메이션 요소의 속성값을 되돌리고 종료한다. |
forwards | 대기 | 시작 프레임(from)에 설정한 스타일을 적용하지 않고 대기한다. |
- | 종료 | 종료 프레임(to)에 설정한 스타일을 적용하고 종료한다. |
backwards | 대기 | 시작 프레임(from)에 설정한 스타일을 적용하고 대기한다. |
- | 종료 | 애니메이션 실행 전 상태로 애니메이션 요소의 속성값을 되돌리고 종료한다. |
both | 대기 | 시작 프레임(from)에 설정한 스타일을 적용하고 대기한다. |
- | 종료 | 종료 프레임(to)에 설정한 스타일을 적용하고 종료한다. |
<!DOCTYPE html>
<html>
<head>
<style>
div {
width: 100px;
height: 100px;
font: bold 1em/100px san-serif;
text-align: center;
color: #fff;
background: red;
margin-bottom: 10px;
position: relative;
/*name duration timing-function delay iteration-count direction fill-mode play-state*/
animation: myAnimation 2s linear 2s;
}
div:nth-of-type(1) {
animation-fill-mode: none;
}
div:nth-of-type(2) {
animation-fill-mode: forwards;
}
div:nth-of-type(3) {
animation-fill-mode: backwards;
}
div:nth-of-type(4) {
animation-fill-mode: both;
}
@keyframes myAnimation {
0% { left: 0px; background: yellow; }
100% { left: 200px; background: blue; }
}
</style>
</head>
<body>
<h1>animation-fill-mode</h1>
<div>none</div>
<p>대기 : 시작 프레임(from)에 설정한 스타일을 적용하지 않고 대기한다.</p>
<p>종료 : 애니메이션 실행 전 상태로 애니메이션 요소의 프로퍼티값을 되돌리고 종료한다.</p>
<div>forwards</div>
<p>대기 : 시작 프레임(from)에 설정한 스타일을 적용하지 않고 대기한다.
<p>종료 : 종료 프레임(to)에 설정한 스타일을 적용하고 종료한다.
<div>backwards</div>
<p>대기 : 시작 프레임(from)에 설정한 스타일을 적용하고 대기한다.
<p>종료 : 애니메이션 실행 전 상태로 애니메이션 요소의 프로퍼티값을 되돌리고 종료한다.
<div>both</div>
<p>대기 : 시작 프레임(from)에 설정한 스타일을 적용하고 대기한다.
<p>종료 : 종료 프레임(to)에 설정한 스타일을 적용하고 종료한다.
</body>
</html>
애니메이션 재생 상태(재생 또는 중지)를 지정한다. 기본값은 running 이다.
<!DOCTYPE html>
<html>
<head>
<style>
div {
width: 100px;
height: 100px;
background: red;
position: relative;
/*name duration timing-function delay iteration-count direction fill-mode play-state*/
animation: move 5s infinite;
}
div:hover {
background: blue;
animation-play-state: paused;
}
div:active {
background: yellow;
animation-play-state: running;
}
@keyframes move {
from { left: 0px; }
to { left: 200px; }
}
</style>
</head>
<body>
<h1>animation-play-state</h1>
<div></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
.box {
position: relative;
width: 100px;
height: 100px;
background-color: red;
animation-name: move;
animation-duration: 5s;
animation-play-state: paused; /* 초기 애니메이션 재생 상태: 정지 */
animation-iteration-count: infinite;
}
/* @keyframes rule */
@keyframes move {
from {
left: 0;
}
to {
left: 300px;
}
}
</style>
</head>
<body>
<div class="box"></div>
<button class="start">start animation</button>
<button class="pause">pause animation</button>
<script>
const box = document.querySelector('.box');
document.querySelector('.start').addEventListener('click', function () {
// trigger animation
// prefixes would be needed...
box.style.animationPlayState = 'running';
});
document.querySelector('.pause').addEventListener('click', function () {
// pause animation
// prefixes would be needed...
box.style.animationPlayState = 'paused';
});
</script>
</body>
</html>
모든 애니메이션 속성을 한번에 지정한다. 값을 지정하지 않은 속성에는 기본값이 지정된다.
animation: name duration timing-function delay iteration-count direction fill-mode play-state
animation-duration은 반드시 지정해야 한다. 지정하지 않는 경우 기본값 0s가 셋팅되어 어떠한 애니메이션도 실행되지 않는다. 기본값은 아래와 같다.
none 0 ease 0 1 normal none running
트랜지션은 CSS 스타일 변경을 부드럽게 표현하기 위해 duration(지속시간)을 부여하여 속도를 조절한다.
애니메이션은 하나의 줄거리(@keyframes)를 구성하여 줄거리 내에서 세부 움직임을 시간 흐름 단위로 제어하여 요소의 움직임을 표현한다.
트랜스폼(Transform)은 요소에 이동(translate), 회전(rotate), 확대축소(scale), 비틀기(skew) 효과를 부여하기 위한 함수를 제공한다. 단 애니메이션 효과를 제공하지는 않기 때문에 정의된 속성이 바로 적용되어 화면에 표시된다. 트랜스폼은 애니메이션 효과를 위해 사용되는 것은 아니지만 애니메이션 효과를 부여할 필요가 있다면 트랜지션이나, 애니메이션과 함께 사용된다.
2D 트랜스폼은 속성값으로 변환함수(transafrom function)을 사용한다. 변환함수는 다음과 같다.
transform function | 설명 | 단위 |
---|---|---|
translate(x, y) | 요소의 위치를 X축으로 x만큼, Y축으로 y만큼 이동시킨다. | px, %, em 등 |
translateX(n) | 요소의 위치를 X축으로 n만큼 이동시킨다. | px, %, em 등 |
translateY(n) | 요소의 위치를 Y축으로 n만큼 이동시킨다. | px, %, em 등 |
scale(x, y) | 요소의 크기를 X축으로 x배, Y축으로 y배 확대 또는 축소시킨다. | 0과 양수 |
scaleX(n) | 요소의 크기를 X축으로 x배 확대 또는 축소 시킨다. | 0과 양수 |
scaleY(n) | 요소의 크기를 Y축으로 y배 확대 또는 축소 시킨다. | 0과 양수 |
skew(x-angle, y-angle | 요소를 X축으로 x 각도 만큼, Y축으로 y 각도만큼 기울인다. | +/-각도(deg) |
skewX(x-angle) | 요소를 X축으로 x 각도만큼 기울인다. | +/-각도(deg) |
skeyY(y-angle) | 요소를 Y축으로 y 각도만큼 기울인다. | +/-각도(deg) |
rotate(angle) | 요소를 angle만큼 회전시킨다. | +/-각도(deg) |
변환함수를 속성값으로 쉼표없이 나열한다. 나열순서에 따라 차례대로 효과가 적용된다.
transform: func1 func2 func3 ...;
<!DOCTYPE html>
<html>
<head>
<style>
.box {
width: 95px;
height: 95px;
line-height: 95px;
color: white;
text-align: center;
border-radius: 6px;
}
.original {
margin: 30px;
border: 1px dashed #cecfd5;
background: #eaeaed;
float: left;
}
.child {
background: #2db34a;
cursor: pointer;
}
.translate {
transform: translate(10px, 50px);
}
.scale {
transform: scale(.75);
}
.skew {
transform: skew(5deg, -20deg);
}
.rotate {
transform: rotate(70deg);
}
.complex {
transform: scale(.5) rotate(20deg);
}
/* Animation Effect */
.translate:hover {
transition: transform 1s linear;
transform: translate(0px, 0px);
}
/* .translate:hover {
animation: translate 1s linear forwards;
}
@keyframes translate {
100% {
transform: translate(0px, 0px);
}
} */
.scale:hover {
transition: transform 1s linear;
transform: scale(1);
}
.skew:hover {
transition: transform 1s linear;
transform: skew(0, 0);
}
.rotate:hover {
transition: transform 1s linear;
transform: rotate(0);
}
.complex:hover {
transition: transform 1s linear;
transform: scale(1) rotate(0);
}
</style>
</head>
<body>
<div class="original box">
<div class="child box translate">translate</div>
</div>
<div class="original box">
<div class="child box scale">scale</div>
</div>
<div class="original box">
<div class="child box skew">skew</div>
</div>
<div class="original box">
<div class="child box rotate">rotate</div>
</div>
<div class="original box">
<div class="child box complex">complex</div>
</div>
</body>
</html>
요소의 기본기준점을 설정할 때 사용된다. 기본기준점은 요소의 정중앙(50%, 50%)이다. 이동은 기준점을 변경하여도 일정 거리만큼 이동하므로 의미가 없다. 설정값으로 %, px, top left, bottom right를 사용할 수 있다. 0, 0은 top left, 100% 100% bottom right와 같은 값이다.
<!DOCTYPE html>
<html>
<head>
<style>
.box {
width: 150px;
height: 150px;
line-height: 150px;
color: white;
text-align: center;
border-radius: 6px;
}
.original {
margin: 20px;
border: 1px dashed #cecfd5;
background: #eaeaed;
float: left;
}
.child {
background: #2db34a;
cursor: pointer;
}
.scale1:hover {
transition: transform 1s linear;
transform-origin: 0 0;
transform: scale(.5);
}
.scale2:hover {
transition: transform 1s linear;
transform-origin: 50% 50%;
transform: scale(.5);
}
.scale3:hover {
transition: transform 1s linear;
transform-origin: 100% 100%;
transform: scale(.5);
}
.translate:hover {
transition: transform 1s linear;
/*transform-origin: 100% 100%;*/
transform: translate(10px, 10px);
}
</style>
</head>
<body>
<div class="original box">
<div class="child box scale1">scale1</div>
</div>
<div class="original box">
<div class="child box scale2">scale2</div>
</div>
<div class="original box">
<div class="child box scale3">scale3</div>
</div>
<div class="original box">
<div class="child box translate">translate</div>
</div>
</body>
</html>
3D 트랜스폼은 속성값으로 변환함수(transform function)를 사용한다. 사용할 수 있는 변환함수는 다음과 같다.
transform function | 설명 | 단위 |
---|---|---|
translate3d(x, y, z) | 요소의 위치를 X축으로 x만큼, Y축으로 y만큼, Z축으로 z만큼 이동시킨다. | px, %, em 등 |
translateX(n) | 요소의 위치를 X축으로 n만큼 이동시킨다. | px, %, em 등 |
translateY(n) | 요소의 위치를 Y축으로 n만큼 이동시킨다. | px, %, em 등 |
translateZ(n) | 요소의 위치를 Z축으로 n만큼 이동시킨다. | px, %, em 등 |
scale3d(x, y) | 요소의 크기를 X축으로 x배, Y축으로 y배, Z축으로 z배 확대 또는 축소 시킨다. | 0과 양수 |
scaleX(n) | 요소의 크기를 X축으로 n배 확대 또는 축소 시킨다. | 0과 양수 |
scaleY(n) | 요소의 크기를 Y축으로 n배 확대 또는 축소 시킨다. | 0과 양수 |
scaleZ(n) | 요소의 크기를 Z축으로 n배 확대 또는 축소 시킨다. | 0과 양수 |
rotate3d(x, y, z) | 요소를 X축으로 x 각도, Y축으로 y 각도, Z축으로 z 각도 회전시킨다. | +/- 각도(deg) |
rotateX(n) | 요소를 X축으로 n 각도 회전시킨다. | +/- 각도(deg) |
rotateY(n) | 요소를 Y축으로 n 각도 회전시킨다. | +/- 각도(deg) |
rotateZ(n) | 요소를 Z축으로 n 각도 회전시킨다. | +/- 각도(deg) |
웹디자인 관점에서 폰트의 선택은 중요한 의미를 갖는다. 대부분의 정보는 텍스트와 이미지로 전달디고 아직은 텍스트가 주를 이루기 때문에 더욱 그러하다. 이전에는 웹에서 사용할 수 있는 아름다운 한글 폰트가 적어 포토샵 등으로 로컬 폰트를 사용하여 텍스트를 이미지로 만들어 사용하였다. 이것은 많은 트래픽을 유발하고 웹크롤러가 정보를 수집할 수 없어 SEO 관점에서도 바람직하지 않다. 아름답고 정돈된 폰트를 사용한다면 그 자체만으로도 훌륭한 웹디자인이 가능하다.
웹 브라우저는 로컬 소프트웨어이므로 당연한 이야기이지만 로컬 환경의 리소스만 사용 가능하다. 폰트는 로컬 환경에 존재하는 리소스의 하나로 로컬 환경에 있지 않은 폰트는 사용할 수 없다.
웹페이지는 불특정 사용자를 위해 제작되기 때문에 어떤 디바이스의 어떤 OS를 사용하는 사용자가 웹페이지에 접근할 지 알 수 없다. 웹페이지를 구성 html, css, javascript 파일이 사용자의 요청에 의해 서버에서 클라이언트로 다운로드되어 실행된느 것과 같이 폰트 또한 서버에서 클라이언트로 다운로드되어 실행될 수 있다면 이 문제는 해결될 수 있다.
이러한 문제를 해결할 수 있는 방법이 바로 웹폰트이다. 웹폰트는 사용자가 웹페이지를 요청한 순간 CSS에 기술된 필요 폰트가 서버에서 클라이언트로 전송된다. 좀 더 구체적으로 말하면 매번 다운로드되는 것은 아니고 클라이언트에 해당 폰트가 존재하지 않을 경우 전송된다.
웹폰트를 사용하는 방법 중 가장 간단한 방법은 CDN 링크를 사용하는 것이다. 다음은 구글에서 제공하는 웹폰트를 사용하는 방법이다.
Google Font 에서 사용하고자 한느 웹폰트를 선택한다. 한글 웹페이지에 자주 사용되는 나눔고딕은 Google Font Early Access에서 찾을 수 있다.
@import url(http://fonts.googleapis.com/earlyaccess/nanumgothic.css);
* { font-family: 'Nanum Gothic', sans-serif; }
@import rule의 url 함수는 서버에서 혹은 지정된 url에서 파일을 찾아 다운로드한다.
Google Font를 사용하기 위해 CDN 링크를 사용하는 방법은 간편한 방법이지만 로딩 속도가 느린 단점이 있다.(로컬 폰트를 사용하는 것에 비해 느리다는 의미이며, 서버 폰트 로딩 방식보다는 빠를 수 있다.) 여러 개의 폰트를 사용한다면 로딩에 더욱 시간이 걸릴 것이다. 또한 CDN 링크를 제공하지 않는 폰트는 사용할 방법이 없다. 이러한 단점을 보완한 방법이 서버 폰트 로딩 방식이다.
@font-face 규칙으로 폰트를 등록하고 font-family 속성으로 폰트를 선택하여 사용할 수 있다.
/* IE 9~ & all browsers */
@font-face {
font-family: myFontName;
src: url("myFont.woff");
}
* { font-family: myFontName, sans-serif; }
폰트 파일을 서버에 두고 요청이 오면 클라이언트로 전송하는 방식이다. 허나 문제는 브라우저에 따라 지원하는 폰트 파일 형식이 다르다는 문제가 있다.
- | EOT | WOFF | SVG | OTF/TTF |
---|---|---|---|---|
IE 6 ~ 8 | O | X | X | X |
IE 9+ | O | O | X | X |
Firefox | X | O | X | O |
Safari | X | O | O | O |
Chrome | X | O | O | O |
Opera | X | O | O | O |
아래 코드는 일반적으로 사용되는 검증된 웹폰트 사용 방법이다. 브라우저에 따라 필요한 폰트만을 다운로드 할 수 있다.
@font-face {
font-family:"Nanum Gothic";
src:url("NanumGothic.eot"); /* IE 9 호환성 보기 모드 대응 */
src:local("☺"), /* local font 사용 방지. 생략 가능 */
url("NanumGothic.eot?#iefix") format('embedded-opentype'), /* IE 6~8 */
url("NanumGothic.woff") format('woff'); /* 표준 브라우저 */
}
* { font-family: "Nanum Gothic", sans-serif; }
영문과 한글을 혼용하는 경우 먼저 영어 폰트, 그 다음 한글 폰트를 지정하여야 한다. 한글 폰트부터 지정하면 영문에도 한글 폰트가 지정된다.
font-family: 'Lora', 'KoPub Batang', 'Times New Roman', serif;
사용자가 어떤 디바이스로 웹사이트를 방문할 지 알 수 없다. layout은 방문자의 화면 해상도를 고려해야한다. 가로폭이 너무 큰 layout을 작성하면 작은 해상도 모니터로 방문하였을 때 가로 스크롤이 생겨서 사용이 불편할 수도 있다.
또한 스마트폰이나 태블릿 등 모바일 기기는 화면이 작기 때문에 가독성에 더욱 신경써야 한다. 보통 웹사이트가 축소되어 가로 스크롤 없이 컨텐츠를 볼 수 있으나 글자가 너무 작아지기 때문이다. 데스크탑용, 테블릿용, 모바일용 웹사이트를 별도 구축할 수도 있지만 One Source Multi Use의 관점에서 올바른 해결책은 아니다.
이러한 문제를 해결하는 방법 중의 하나가 반응형 웹디자인(Responsive Web Design)이다. 해면 해상도에 따라 가로폭이나 배치를 변경하여 가독성을 높이는 것이다. 즉, 하나의 웹사이트를 구축하여 다양한 디바이스의 화면 해상도에 최적화된 웹사이트를 제공하는 것이다.
또한 최근 모바일 웹페이지는 대부분 애플리케이션의 형태로 진화하고 있어 앱인지 웹인지 구분이 어려울 정도이다. HTML5/ CSS3/ Javascript 만으로 네이티스 앱과 차이를 느낄 수 없는 앱을 만들 수 있다. 다음은 최근 관심을 끌고 있는 Web App Framework이다.
viewport란 웹페이지의 가시영역을 의미한다. viewport는 디바이스에 따라 차이가 있다. 예를 들어 모바일 브라우저는 주화면이 세로 화면이고 윈도우 resize가 불가하며 화면 터치를 사용하는 등 데스크탑 브라우저와 구성이나 형태가 다르다. 또한 모바일의 화면은 데스크탑 화면보다 훨씬 작으므로 데스크탑용 웹페이지를 그대로 모바일에 출력하면 가독성이 현저히 나빠진다. 따라서 viewport를 이용하여 디바이스의 특성과 디바이스의 화면 크기 등을 고려하여 각종 디바이스 사용자에게 최적
meta tag는 브라우저 혹은 검색엔진최적화(SEO)를 위해 검색엔진에게 메타데이터를 전달하기 위해 사용된다.
viewport meta tag는 브라우저의 화면 설정과 관련된 정보를 제공한다.
속성 | Description | 사용예 |
---|---|---|
width | viewport 너비(px). 기본값: 980px | width=240 |
width=device-width | ||
height | viewport 높이(px) | height=800 |
width=device-height | ||
initial-scale | viewport초기 배율 | initial-scale=1.0 |
user-scale | 확대 축소 가능 여부 | user-scale=no |
maximum-scale | viewport 최대 배율 | maximum-scale=2.0 |
minimum-scale | viewport 최소 배율 | minimum-scale=1.0 |
meta tag에서는 px단위를 사용하며 단위 표현은 생략한다. 복수개의 속성을 사용할 때는 쉼표(,)로 구분한다.
일반적으로 viewport meta tag는 모바일 디바이스에서만 적용된다.
아래는 가장 일반적인 viewport 설정으로 가로폭을 디바이스의 가로폭에 맞추고 초기 화면 배율을 100%로 설정하는 것을 의미한다.
<meta name="viewport" content="width=device-width, initial-scale=1.0">
이것은 서로 다른 미디어 타입(print, screen,...)에 따라 각각의 styles을 지정하는 것을 가능하게 한다. 다음은 일반 화면(screen)과 인쇄장치 별로 서로 다른 style을 지정하는 코드이다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
@media screen {
* { color: red; }
}
@media print {
* { color: blue; }
}
</style>
</head>
<body>
<h1>@media practice</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>
반응형 웹디자인에 사용되는 가장 중요한것은 @media이다.
@media을 사용하여 미디어 별로 style을 지정하는 것을 Media Query라 한다. 디바이스를 지정하는 것 뿐만 아니라 디바이스의 크기나 비율까지 구분할 수 있다.
다음은 Media Query의 문법이다.
@media screen and (min-width: 480px) {
body {
background-color: lightgreen;
}
}
아래의 표는 Media Query의 표현식에서 사용할 수 있는 속성이다.
속성 | 설명 |
---|---|
width | viewport 너비(px) |
height | viewport 높이(px) |
device-width | 디바이스의 물리적 너비(px) |
device-height | 디바이스의 물리적 높이(px) |
orientation | 디바이스 방향(가로 방향: landscape, 세로 방향: portrait) |
device-aspect-ratio | 디바이스의 물리적 width |
color | 디바이스에서 표현 가능한 최대 색상 비트 수 |
monochrome | 흑백 디아비스의 픽셀 당 비트 수 |
resolution | 디바이스 해상도 |
orientation을 제외한 모든 속성은 max/min 접두사를 사용할 수 있다.
일반적으로 반응형 웹 디자인은 viewport 너비(width 프로퍼티)를 기준으로 한다.
viewport의 width 속성을 이용하여 viewport 너비에 따라 반응 하는 범위(breakpoint)를 지정할 수 있다.
viewport의 width 프로퍼티를 이용하여 viewport 너비에 따라 반응하는 범위(breakpoint)를 지정할 수 있다.
/*========== Mobile First Method ==========*/
/* All Device */
/* Custom, iPhone Retina : 320px ~ */
@media only screen and (min-width : 320px) {
}
/* Extra Small Devices, Phones : 480px ~ */
@media only screen and (min-width : 480px) {
}
/* Small Devices, Tablets : 768px ~ */
@media only screen and (min-width : 768px) {
}
/* Medium Devices, Desktops : 992px ~ */
@media only screen and (min-width : 992px) {
}
/* Large Devices, Wide Screens : 1200px ~ */
@media only screen and (min-width : 1200px) {
}
/*========== Non-Mobile First Method ==========*/
/* All Device */
/* Large Devices, Wide Screens : ~ 1200px */
@media only screen and (max-width : 1200px) {
}
/* Medium Devices, Desktops : ~ 992px */
@media only screen and (max-width : 992px) {
}
/* Small Devices, Tablets : ~ 768px */
@media only screen and (max-width : 768px) {
}
/* Extra Small Devices, Phones : ~ 480px */
@media only screen and (max-width : 480px) {
}
/* Custom, iPhone Retina : ~ 320px */
@media only screen and (max-width : 320px) {
}
다음은 임의로 해상도를 3단계로 구분하여 breakpoint를 정의한 예제이다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* 801px ~ */
* { color: black; }
/* ~ 800px */
@media screen and (max-width: 800px) {
* { color: blue; }
}
/* ~ 480px */
@media screen and (max-width: 480px) {
* { color: red; }
}
</style>
</head>
<body>
<h1>@media practice</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>
다음은 화면이 세로일 때, 가로일 때를 구분하는 예제이다. 주의할 점은 데스크탑은 언제나 가로 화면이기 때문에 device-width로 스마트폰의 해상도를 지정하지 않으면 데스크탑에서도 가로화면 시 style이 적용되는 문제가 발생한다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* 세로 */
* { color: black; }
/* 가로 */
/* Desktop의 화면은 가로화면(landscape)이므로 아래 rule이 적용된다. */
/*
@media screen and (orientation: landscape) {
{ color: blue; }
}
*/
/* Landscape */
@media screen
/* 디바이스가 모바일일때(device-width 0 ~ 768px) */
and (max-device-width: 760px)
/* 가로 */
and (orientation: landscape) {
* { color: blue; }
}
</style>
</head>
<body>
<h1>@media practice: orientation</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>
Flexbox는 모던 웹을 위하여 제안된 기존 layout보다 더 세련된 방식의 니즈에 부합하기 위한 CSS3의 새로운 layout 방식이다.
요소의 사이즈가 불명확하거나 동적으로 변화할 때도 유연한 레이아웃을 실현할 수 있다. 복잡한 레이아웃이라도 적은 코드로 보다 간단하게 표현할 수 있다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Flexbox Layout Example</title>
<style>
.flex-container {
margin: 10px;
padding: 15px;
border-radius: 5px;
background: #60B99A;
}
.flex-item {
margin: 10px;
padding: 20px;
color: #fff;
text-align: center;
border-radius: 5px;
background: #4584b1;
}
</style>
</head>
<body>
<div class="flex-container">
<div class="flex-item">1</div>
<div
위의 코드에서 div요소는 block 요소이기에 수직 정렬된다. 이를 수평 정렬로 바꿀려면 자식요소를 inline-block으로 지정하거나 float 속성을 지정한다.
.flex-item {
display: inline-block;
/* or */
float: left;
}
이때 각 자식 요소를 부모 요소 내에서 정렬하기 위해서는 각 자식 요소의 너비를 %로 지정하는 등 번거로운 처리가 필요하다. 자식 요소의 사이즈가 불명확하거나 동적으로 변화할 때에는 더욱 처리가 복잡해 진다. grid 시스템을 사용할 수도 있으나 이 또한 새로운 학습이 필요하고 라이브러리를 로드해야하는 번거로움이 존재한다.
Flexbox를 사용하여 위 예제를 부모 요소 내에서 균등 수평 정렬을 하고자하면 부모 요소에 2행을 추가하면된다.
.flex-container {
display: flex;
justify-content: space-around;
}
위의 Flexbox를 사용하면 기존에 방식에 비해 매우 간단히 레이아웃을 처리할 수 있다.
Flexbox 의 장점을 정리하면 다음과 같다.
- 1줄의 코드 추가로 수평 정렬이 가능하다.
- 요소의 상하좌우 정렬, 순서 변경이 간단하다.
- 요소가 간격 조절이 간단하다.
- 서로 다른 height를 갖는 요소의 수평정렬 시 간단한 상하중앙 정렬이 가능하다.
비교적 최신 브라우저가 아니면 벤더 프리픽스를 사용하여야 하고 IE 계열은 IE8, 9의 경우 지원하지 않으며 IE10, 11의 경우도 일부 지원하기에 주의가 필요하다.
Flexbox의 레이아웃은 flex item이라 불리는 복수의 자식 요소와 이들을 내포하는 flex-container 부모 요소로 구성된다.
flexbox를 사용하기 위해서는 HTML 부모 요소에 display:flex를 지정해야한다.
.flex-container {
display: flex;
}
만일 부모 요소가 inline 요소인 경우 inline-flex를 지정한다.
.flex-container {
display: inline-flex;
}
flex 또는 inline-flex는 부모 요소에 반드시 지정해야하는 유일한 속성이며 자식 요소는 자동적으로 flex item이 된다.
flex-direction 속성은 flex 컨테이너의 주축(main axis) 방향을 설정한다.
flex-direction: row;
좌에서 우로(ltr) 수평 배치된다. flex-direction 속성의 기본값이다.
.flex-container {
flex-direction: row;
}
flex-direction: row-reverse;
우에서 좌로(rtl) 수평 배치된다.
.flex-container {
flex-direction: row-reverse;
}
flex-direction: column;
위에서 아래로 수직 배치된다.
.flex-container {
flex-direction: column;
}
flex-direction: column-reverse;
아래에서 위로 수직 배치된다.
.flex-container {
flex-direction: column-reverse;
}
flex-wrap 속성은 flex 컨테이너의 복수 flex item을 1행으로 또는 복수행으로 배치한다. flex-wrap 속성은 flex 컨테이너의 width보다 flex item 들의 width의 합계가 더 큰경우, 한줄로 표현할 것인지, 여러 줄로 표현할 것인지를 지정한다.
flex-wrap: nowrap;
flex item을 개행하지 않고 1행에 배치한다. flex-wrap 속성의 기본값이다.
각 flex item의 폭은 flex container에 들어갈 수 있는 크기로 축소된다.
.flex-container {
flex-wrap: nowrap;
}
<!DOCTYPE html>
<html>
<head>
<title>Flexbox</title>
<meta charset="UTF-8">
<style>
.flex-container {
width: 500px;
margin: 10px;
padding: 15px;
border-radius: 5px;
background: #60B99A;
display: flex;
flex-wrap: nowrap;
}
.flex-item {
margin: 10px;
padding: 20px;
color: #fff;
text-align: center;
border-radius: 5px;
background: #4584b1;
}
</style>
</head>
<body>
<div class="flex-container">
<div class="flex-item">11111</div>
<div class="flex-item">22222</div>
<div class="flex-item">33333</div>
<div class="flex-item">44444</div>
<div class="flex-item">55555</div>
</div>
</body>
</html>
하지만 flex item 들의 width의 합계가 flex 컨테이너의 width보다 큰 경우 flex 컨테이너를 넘치게 된다. 이때 overflow: auto;를 지정하면 가로 스크롤이 생기며 컨테이너를 넘치지 않는다.
flex-wrap: wrap;
flex item 들의 width의 합계가 flex 컨테이너의 width 보다 더 큰경우, flex item을 복수행에 배치한다. 기본적으로 좌에서 우로, 위에서 아래로 배치된다.
.flex-container {
flex-wrap: wrap;
}
flex-wrap:wrap-reverse;
flex-wrap: wrap;과 동일하나 아래에서 위로 배치된다.
.flex-container {
flex-wrap: wrap-reverse;
}
flex-flow 속성은 flex-direction 속성과 flex-wrap 속성을 설정하기 위한 shorthand이다. 기본값은 row nowrap 이다.
.flex-container {
flex-flow: <flex-direction> || <flex-wrap>;
}
flex container의 main axis를 기준으로 flex item을 수평 정렬한다.
justify-content: flex-start;
main start(좌측)를 기준으로 정렬한다. justify-content 속성의 기본값이다.
.flex-container {
justify-content: flex-start;
}
justify-content:flex-end;
main end(우측)를 기준으로 정렬한다.
.flex-container {
justify-content: flex-end;
}
justify-content: center;
flex container의 중앙에 정렬한다.
.flex-container {
justify-content: center;
}
justify-content: space-between;
첫번째와 마지막 flex item은 자와 측면에 정렬되고 나머지와 균등한 간격으로 정렬된다.
.flex-container {
justify-content: space-between;
}
justify-content: space-round
모든 flex item은 균등한 간격으로 정렬된다.
.flex-container {
justify-content: space-around;
}
flex item을 flex container 의 수직 방향(cross axis)으로 정렬한다. align-items 속성은 모든 flex item에 적용된다.
align-items: stretch;
모든 flex item은 flex container의 높이(cross start에서 cross end까지의 높이)에 꽉찬 높이를 갖는다. align-items 속성의 기본값이다.
.flex-container {
align-items: stretch;
}
align-items: flex-start;
모든 flex item은 flex container의 cross start 기준으로 정렬된다..
.flex-container {
align-items: flex-start;
}
align-items: flex-end;
모든 flex item은 flex container의 cross end 기준으로 정렬된다.
.flex-container {
align-items: flex-end;
}
align-items: center;
모든 flex item은 flex container의 cross axis의 중앙에 정렬된다.
.flex-container {
align-items: center;
}
align-items: baseline;
모든 flex item은 flex container의 baseline을 기준으로 정렬된다.
.flex-container {
align-items: baseline;
}
flex container의 cross axis를 기준으로 flex item을 수직 정렬한다.
참고로 justify-content 속성은 flex container의 main axis를 기준으로 flex item을 수평 정렬한다.
align-content: stretch;
모든 flex item은 flex item의 행 이후에 균등하게 분배된 공간에 정렬되어 배치된다. align-content 속성의 기본값이다.
.flex-container {
align-content: stretch;
}
align-content: flex-start;
.flex-container {
align-content: flex-start;
}
align-content: flex-end;
모든 flex item은 flex container의 cross end 기준으로 stack 정렬된다.
.flex-container {
align-content: flex-end;
}
align-content: center;
모든 flex item은 flex container의 cross axis의 중앙에 stack 정렬된다.
.flex-container {
align-content: center;
}
align-content: space-between;
첫번째 flex item의 행은 flex container의 상단에 마지막 flex item의 행은 flex container 하단에 배치되며 나머지 행은 균등 분할된 공간에 배치 정렬된다.
.flex-container {
align-content: space-between;
}
align-content: space-around;
모든 flex item은 균등 분할된 공간 내에 배치 정렬된다.
.flex-container {
align-content: space-around;
}
float, clear, vertical-align 속성은 flex item에 영향을 주지 않는다.
flex item의 배치 순서를 지정한다. HTML 코드를 변경하지 않고 order 속성값을 지정하는 것으로 간단히 재배치할 수 있다. 기본 배치 순서는 flex container에 추가된 순서이다. 기본값은 0이다.
.flex-item {
order: 정수값;
}
flex item의 너비에 대한 확대 인자(flex grow factor)를 지정한다. 기본값은 0이고 음수값은 무효하다.
.flex-item {
flex-grow: 양의 정수값;
}
모든 flex item이 동일한 flex-grow 속성값을 가지면 모든 flex item은 동일한 너비를 갖는다.
두번째 flex item의 flex-grow 속성값을 3으로 지정하면 다른 flex item보다 더 넓은 너비를 갖는다.
flex item의 너비에 대한 축소 인자(flex shrink factor)를 지정한다. 기본값 1이고 음수값은 무효하다. 0을 지정하면 축소가 해제되어 원래의 너비를 유지한다.
.flex-item {
flex-shrink: 양의 정수값;
}
기본적으로 모든 flex item은 축소된 상태로 지정(기본값 1)하고 두번째 flex item만 축소를 해제(flex-shrink: 0;)하면 원래의 너비를 유지한다.
flex item의 너비 기본값을 px, % 등의 단위로 지정한다. 기본값은 auto이다.
.flex-item {
flex-basis: auto | <width>;
}
flex-grow, flex-shrink, flex-basis 속성의 shorthand이다. 기본값은 0 1 auto이다.
W3C에서는 이 속성을 사용하는 것 보다 개별적으로 기술하는 것을 권고하고 있다.
.flex-item {
flex: none | auto | [ <flex-grow> <flex-shrink>? || <flex-basis> ];
}
align-items 속성(flex container속성으로 flex item을 flex container의 수직 방향(cross axis)으로 정렬한다.)보다 우선하여 개별 flex item을 정렬한다. 기본값은 auto이다.
.flex-item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
3번째, 4번째 flex item은 align-self 속성값이 우선 적용되어 정렬된다.