์ค๋๋ง์ html, css, javascript๋ก ์ฝ๋ฉ์ ํด์ผ ํ๋ค ๋ณด๋, ์ ๊ธฐ์กด์ฒ๋ผ ํ๊ธฐ์๋ ๊ท์ฐจ๋์ฆ์ด ์๊ฒจ๋ฒ๋ ธ์ต๋๋ค. ๐
๊ทธ๋์์ ๋ฑํ ๊ด์ฌ ๊ฐ์ ๋งํ ์ผ์ ์์์ผ๋ ๊ท์ฐฎ์ ๊ฑด ๋๋ฌด ์ซ์ผ๋ ์๋ ๊ด์ฌ์ด ์๊ธฐ๊ฒ ๋๋ฉด์ ์ด๋ฒ ๊ธฐํ์ ์ ๋ฌธํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
๊ณต์๋ฌธ์๋ฅผ ๋ณด๊ณ ํ๋์ฉ ๋ฐ๋ผํ๊ฑฐ๋ ๊ฐ์๋ฅผ ๋ณด๊ณ ๊ณต๋ถํด๋ ์ข์ง๋ง,
์ ๋ฐ์ ์ผ๋ก ํ ๋ฒ ์งง๊ฒ ๊ฒํฅ๊ธฐ ์์ผ๋ก ์์ฑํด๋ณด๊ณ ๊ฐ์๋ฅผ ๋ค์ผ๋ฉด ์ดํดํ๋๋ฐ ์ข ๋ ๋์์ด ๋์ง ์์๊น ์ถ์ต๋๋ค.
์ฐธ์กฐ: https://sass-lang.com/
1. ํ๊ฒฝ์ธํ
๊ทธ๋ด ๋ฆฌ ์๊ฒ ์ง๋ง node๊ฐ ์๋ค๋ฉด ์ค์น
๊ธฐ์กด ๋ฒ์ (node-sass, libsass)๋ ํ์ง๋์๋ค๊ณ ํ๋ Dart Sass๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ํ๋ค์.
npm install -g sass
// ๋ง์ฝ ์จ๋ณด๊ณ ๋ค์ ์ญ์ ํ๊ณ ์ถ๋ค๋ฉด
npm remove -g sass
sass-practice๋ผ๋ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ vscode๋ฅผ ์ด์ด์ค๋๋ค.
mkdir sass-practice
cd sass-practice
code .
๊ทธ๋ฆฌ๊ณ src ๋๋ ํฐ๋ฆฌ๋ฅผ src ๋๋ ํฐ๋ฆฌ์์ ์์ฑํ ๋ค scss ํ์ผ์ ๋ง๋ค์ด๋ด ๋๋ค.
// src/style.scss
$color: red;
์ด์ ์ด ํ์ผ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฝ์ ์ ์๋๋ก css ํ์ผ๋ก ๋ณํ์์ผ์ค์ผ ํฉ๋๋ค.
๋ณํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
sass scss๋๋ ํฐ๋ฆฌ๋ช
/cssํ์ผ๋ช
:๋๋ ํฐ๋ฆฌ๋ช
/ํ์ผ๋ช
// ์ผ๊ด๋ณํ
sass --watch scss๋๋ ํฐ๋ฆฌ๋ช
:css๋๋ ํฐ๋ฆฌ๋ช
// ์ค์๊ฐ๋ณํ
์ด๋ ๊ฒ sass ๋ค์ scss๊ฐ ์ ์ฅ๋์ด์๋ ๋๋ ํฐ๋ฆฌ๋ช : css๋ก ๋ณํ๋ ํ์ผ์ด ์ ์ฅ๋ ๋๋ ํฐ๋ฆฌ๋ช ์ ์ ์ด์ฃผ๋ฉด ๋ฉ๋๋ค.
--watch ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ ์ฅํ ๋๋ง๋ค ์ค์๊ฐ์ผ๋ก ๋ณํ๋ผ์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ง์ฝ node๋ฅผ ํตํด ์ค์ ํด์ ์ฐ๊ณ ์ถ๋ค๋ฉด package.json์์ ์คํ ๋ช ๋ น์ด๋ฅผ ์ถ๊ฐํ๋ฉด ์คํํ ๋๋ง๋ค ๊ฒฝ๋ก๋ฅผ ์์ฑํ์ง ์์๋ ๋ฉ๋๋ค.
npm init -y๋ฅผ ํตํด package.json ํ์ผ์ ์์ฑํด ์ฃผ์ธ์.
๊ทธ๋ฆฌ๊ณ package.json ํ์ผ์ ์ด์ด ์คํ ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํด ์ค๋๋ค.
{
"name": "sass-practice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build:sass": "sass src:dist", // ์ผ๊ด ๋ณํ ์ถ๊ฐ
"watch:sass": "sass --watch src:dist " // ์ค์๊ฐ ๋ณํ ์ถ๊ฐ
},
"keywords": [],
"author": "",
"license": "ISC"
}
์ด๋ ๊ฒ ํ๋ฉด ์ด์ ์ฐ๋ฆฌ๋ ์ ๋ ์ปดํ์ผ์ ํ๊ธฐ ์ํด npm run watch:sass ๋ผ๋ ๋ช ๋ น์ด๋ง ์น๋ฉด ๋ฉ๋๋ค.
2. ์ฌ์ฉํ๊ธฐ
์ ๊ฐ ๊ฐ๋จํ๊ฒ ์์ฑํด๋ณธ ์ํ์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ํฌํจํ๊ณ ์์ต๋๋ค.
๋ณ์์ฌ์ฉ, mixin ์ฌ์ฉ, extend ์ฌ์ฉ, for / if ๋ฌธ ์ฌ์ฉ
์ฐ์ ๋งํฌ์ ๊ณผ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํด ์ค๋๋ค.
<div class="wrap theme1">
<div class="inner">
<button class="changeTheme btn">Chagen theme</button>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Odio quas, quos doloremque, temporibus eveniet sed explicabo, reiciendis ea assumenda quam amet vitae. Eveniet repellat ipsam adipisci, nostrum ipsum inventore totam?
</p>
<ul class="list">
<li class="item">html</li>
<li class="item">sass</li>
<li class="item">javascript</li>
<li class="item">react</li>
</ul>
<span class="message">I am message </span>
</div>
</div>
<script>
const btn = document.querySelector('.changeTheme');
const wrap = document.querySelector('.wrap');
btn.addEventListener('click', function(){
if(wrap.classList.contains('theme1')) {
wrap.classList.replace('theme1', 'theme2');
} else {
wrap.classList.replace('theme2', 'theme1');
}
})
</script>
์คํฌ๋ฆฝํธ๋ ๊ฐ๋จํ๊ฒ wrap์ theme1 ํด๋์ค๋ช ๊ณผ theme2 ํด๋์ค๋ช ์ ํ ๊ธ ์์ผ์ฃผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
scss์์ template๋ฅผ ๋ง๋ค๊ณ ๊ฐ๊ฐ ํด๋์ค ๋ช ์ผ ๋ parameter๊ฐ์ ์ฃผ์ด ๋ค๋ฅด๊ฒ ํํํ๋ ค๊ณ ํฉ๋๋ค.
์ด์ src/style.scss์์ template์ ์์ฑํฉ๋๋ค.
1. MIXIN
$padding: 2rem;
@mixin template($theme_name, $theme_bg, $theme_color) {
padding: $padding;
background: $theme_bg;
color: $theme_color;
}
.theme1 {
@include template("theme1", darkred, lightpink);
}
.theme2 {
@include template("theme2", darkblue, lightblue );
}
๊ตณ์ด ์ฌ์ฌ์ฉ์ฑ์ด ์๋ ๋ณ์ ์ ์ธ์ ์ง์ํ๋ ๊ฒ ์ข๊ฒ ์ง๋ง ๋ค์๊ณผ ๊ฐ์ด mixin๋ด๋ถ์์๋ $padding์ ์ ๊ทผํ ์ ์๋ค๋ ๊ฒ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ์จ๋ณด์์ต๋๋ค.
mixin ์ ์ธ์ @mixin, ์ฌ์ฉ ์์๋ @include๋ฅผ ์ฌ์ฉํฉ๋๋ค.
$theme_bg, $theme_color๋ฅผ ๋ณด๋ฉด mixin์์ ํ๋ผ๋ฏธํฐ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
2. extends
$msg_color: lightgreen;
{ ... }
.message {
color: $msg_color;
font-size: 1.2rem;
font-weight: bold;
text-decoration: underline;
}
.theme1 {
@include template("theme1", darkred, lightpink);
.message {
$msg_color: rgb(241, 146, 241); // ๋ณ์ ์ฌ์ ์ธ
@extend .message; // extend
color: $msg_color; // ์ฌ์ ์ธ๋ ๋ณ์ ์ ์ฉ
}
}
$๋ก ์ ์ธํ ๋ณ์๋ฅผ ๋ถ๋ชจ ํด๋์ค ๋ด์์ ์ฌ์ ์ธ ํ ์๋ ์์ต๋๋ค.
๋ํ .message๋ผ๋ ์คํ์ผ์ extend๋ฅผ ํตํด ๊ฐ์ ธ๋ค ์ฌ์ฉํ ์๋ ์๋ค์.
3. if๋ฌธ
@mixin btn($theme_name) {
border: 0 none;
padding: 4px 8px;
border-radius: 2px;
cursor: pointer;
@if $theme_name == "theme1" {
background: palevioletred;
color: white;
} @else {
background: skyblue;
color: darkblue;
}
}
.theme1 {
button {
@include btn("theme1");
}
{...}
}
.theme2 {
button {
@include btn("theme2");
}
{ ... }
}
๊ฐ๊ฐ ๋ค๋ฅธ ํ๋ผ๋ฏธํฐ ๊ฐ์ ์ฃผ์ด ํ๋ผ๋ฏธํฐ ๊ฐ์ ๋งค์นญ ์ฌ๋ถ๋ฅผ ํ์ธํ์ฌ ๋ค๋ฅธ ์คํ์ผ์ ์ค ์ ์์ต๋๋ค.
ํจ์ ์ ์ธ ์์๋ @๊ฐ ๋ถ์ต๋๋ค. ๋ง์ฝ return ํ ์ผ์ด ์๋ค๋ฉด @return ์ด๋ ๊ฒ ์จ์ค์ผ ํฉ๋๋ค.
4. for๋ฌธ
.list {
list-style-type: none;
padding: 0;
@for $i from 1 through 4 {
.item:nth-child(#{$i}):before {
content: $i + ': ';
margin-right: 5px;
}
}
}
for๋ฌธ์ ์ฌ์ฉํ์ฌ nth-child๋ฅผ ํตํด ์์ ์นด์ดํธ๋ฅผ ๋ถ์์ต๋๋ค.
์ค๋ ํฐ ๋ด๋ถ์์ ๋ณ์๋ฅผ ์ฌ์ฉํ ๋์๋ #{ } ์์ ์จ์ค์ผ ํ๋ค์.
ํด๋น ๋ชฉ๋ก์ ๋ฐฐ์ด ๋ณ์์ ๋ด์ length๊ฐ์ ์ฒดํฌํด์ ์ฌ์ฉํด๋ ๋์ง๋ง, ์ด๋ ๋ ์ ๋ ๋ ์ด๋ฏธ html์์ ์ ์ธํ๋ ๋ถ๋ถ์ ํ๋ฒ ๋ ์จ์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ 4๋ก ๋ฐ์์ต๋๋ค. ๋ง์ฝ ๋ ์ฌ๋ฌ ๊ตฐ๋ฐ์์ ์ฌ์ฉํด์ผ ํ๋ค๊ณ ํ๋ฉด ๋ฐฐ์ด์ ์ ์ธํด์ ์ฐ๋ ๊ฒ์ด ํจ์ฌ ํธ๋ฆฌํ ๊ฒ ๊ฐ์ต๋๋ค.
5. ํ์ผ ๋ถ๋ฆฌํ๊ธฐ
๊ธฐ์กด์ css๋ด์์ ์ธ๋ถ css๋ฅผ ๋ถ๋ฌ์ฌ ๋๋ ๋์ผํฉ๋๋ค.
@include๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// src/mixin.scss
@mixin template($theme_name, $theme_bg, $theme_color) {
...
}
@mixin btn($theme_name) {
...
}
@import './mixins.scss';
{...}
์ด๋ ๊ฒ ๋ณ์๋ mixin์ ํํ์ผ์ ๊ด๋ฆฌํ๋ฉด ๋ ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฒฐ๊ณผ
'๊ฐ๋ฐ ๐พ > HTML,CSS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํฐํธ๋ฅผ ํ๊ธ๊ณผ ์์ด,์ซ์ ๋ฐ๋ก ์ ์ฉํ๊ธฐ (feat. unicode-range) (0) | 2021.07.19 |
---|---|
Live sass compiler ์ฌ์ฉํ๊ธฐ (0) | 2021.07.06 |
CSS์์ ๋ณ์ ์ฌ์ฉํ๊ธฐ (0) | 2021.06.30 |
select ํ๊ทธ ์ปค์คํ ํ๊ธฐ, ํน์ ์ง์ ๋ง๋ค๊ธฐ (feat. javascript) (8) | 2021.06.18 |
input search x ๋ฒํผ ์ญ์ ๋ฐ ํด๋ฆฌ์ด ๋ฒํผ ์ง์ ๋ง๋ค์ด ๋ฃ๊ธฐ (0) | 2021.06.15 |