• [JS30] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ CSS ๋ณ€์ˆ˜(์‚ฌ์šฉ์ž ์ •์˜ ์†์„ฑ) ์กฐ์ ˆํ•˜๊ธฐ

    2019. 1. 7.

    by. ๋‚˜๋‚˜ (nykim)

    ๐Ÿ”ฅJavascript 30 - Day 03๐Ÿ”ฅ


    1. ๋งˆํฌ์—…/์Šคํƒ€์ผ๋ง

    ์ด๋ฒˆ์—๋Š” CSS๋ฅผ JS๋กœ ์ œ์–ดํ•ด ๋ด…์‹œ๋‹ค! ์šฐ์„  ์ ๋‹นํžˆ ๋งˆํฌ์—…ํ•˜๊ณ  ์ ๋‹นํžˆ ์Šคํƒ€์ผ๋ง ํ•ฉ๋‹ˆ๋‹ค(์ฐธ ์‰ฝ์ฃ ?).
    ์ž์„ธํ•œ html, css์ฝ”๋“œ๋Š” Codepen ๊ฒฐ๊ณผ๋ฌผ ์— ์žˆ์–ด์š”! >
    ์ œ์–ด ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์€ 'ํฐํŠธ ์‚ฌ์ด์ฆˆ/๋ฉ”์ธ ์ปฌ๋Ÿฌ/์ด๋ฏธ์ง€ ๋ธ”๋Ÿฌ์ฒ˜๋ฆฌ' ์š”๋ ‡๊ฒŒ 3๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

    <!-- HTML -->
    
    <div class="wrap">
        <h1>Update CSS Variables With <em>JS</em></h1>
            <div class="option">
    	    <strong>Option</strong>
    	    <div class="block">
    		 <label for="textSize" class="opt-title">Font size</label>
    		 <input type="range" name="textSize" min="11" max="18" value="14" data-sizing="px" />
    	    </div>
    	    <div class="block">
    		 <label for="mainColor" class="opt-title">Main Color</label>
    		 <input type="color" name="mainColor" value="#ffc600">
    	    </div>
    	    <div class="block">
    		 <label for="blur" class="opt-title">Background Blur</label>
    		 <input type="range" name="blur" min="0" max="10" value="0" data-sizing="px" />
    	    </div>
    	</div>
    	
    	<div class="content">
    	    <article class="article-1">
    		 <img src="http://unsplash.it/960?image=183" alt="image" class="img">
    		 <div class="txt">{ํ…์ŠคํŠธ}</div>
    	    </article>
    	    <article class="article-2">
    		 <img src="http://unsplash.it/960?image=179" alt="image" class="img">
    		 <div class="txt">{ํ…์ŠคํŠธ}</div>
    	    </article>
                <article class="article-3">
    		 <img src="http://unsplash.it/960?image=228" alt="image" class="img">
    		 <div class="txt">{ํ…์ŠคํŠธ}</div>
    	    </article>
    	</div>
    </div>
    

    2. :root ์†์„ฑ ์ž‘์„ฑํ•˜๊ธฐ

    ๊ทธ ๋‹ค์Œ, ์•„๋ž˜์™€ ๊ฐ™์ด CSS๋ฅผ ์ถ”๊ฐ€ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

    :root {
        /*์ฝ”๋“œ ์ž‘์„ฑ*/
    }    

    ์ž ๊น!!! ๋„๋Œ€์ฒด :root๊ฐ€ ๋ญ์ง€?! ์‹ถ์€ ์‚ฌ๋žŒ(๋ฐ”๋กœ ์ ‘๋‹ˆ๋‹ค)์„ ์œ„ํ•ด ์งš๊ณ  ๋„˜์–ด๊ฐ€์ฃ !

    :root ์„ ํƒ์ž๋Š” ๋ฌธ์„œ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. HTML ๋ฌธ์„œ์—์„œ ์ตœ์ƒ์œ„ ์š”์†Œ๋ผ ํ•จ์€ ๋‹น์—ฐํžˆ <html/>์„ ๋งํ•˜๊ฒ ์ฃ !
    ์•„๋‹ˆ ๊ทธ๋Ÿผ, :root{}๋ž‘ html{}์ด๋ž‘ ๊ฐ™์€ ๊ฑฐ ์•„๋‹Œ๊ฐ€ ์‹ถ์€๋ฐ์š”. :root๋Š” ๊ฐ€์ƒ ์„ ํƒ์ž์ด๊ธฐ ๋•Œ๋ฌธ์—, html ์…€๋ ‰ํ„ฐ๋ณด๋‹ค๋„ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ :root์™€ html์— ๋Œ€ํ•œ ์Šคํƒ€์ผ์„ ๋™์‹œ์— ์„ ์–ธํ•˜๋ฉด, :root์— ๋Œ€ํ•œ ์Šคํƒ€์ผ์ด ์šฐ์„ ๋ฉ๋‹ˆ๋‹ค.

    ํ ... ๊ทธ๋Ÿผ, ์ด :root๋Š” ์–ด๋””์—๋‹ค ์จ๋จน์„ ์ˆ˜ ์žˆ์„๊นŒ์š”? ๋ฐ”๋กœ ์ „์—ญ ์Šค์ฝ”ํ”„์˜ CSS ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    CSS ๋ณ€์ˆ˜๋ผ๊ณ  ํ•˜๋‹ˆ๊นŒ SASS์—์„œ ์‚ฌ์šฉํ•˜๋Š” $var = red;๊ฐ€ ๋– ์˜ค๋ฅด๋Š”๋ฐ, ์ด๊ฑฐ๋ž‘์€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. SASS๊ฐ€ ์•„๋‹ˆ๋ผ CSS๊ฑฐ๋“ ์š”!! (CSS๋„ ๋ณ€์ˆ˜๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋‹ˆ ์ถฉ๊ฒฉ....)

    CSS ๋ณ€์ˆ˜(์ •ํ™•ํžˆ๋Š” '์‚ฌ์šฉ์ž ์ •์˜ CSS ์†์„ฑ'์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค)๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ, --๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

    :root {
        --textSize: 14px;
    }  

    ์ด๋ ‡๊ฒŒ ์„ ์–ธํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ์†์„ฑ์€ var()๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    p {
        font-size: var(--textSize);
    }

    ์ด์ œ --textSize์˜ ๊ฐ’์„ ๋ฐ”๊พธ๋ฉด ๊ทธ์— ๋”ฐ๋ผ ํฐํŠธ ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ด์–ด์„œ :root์— ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋“ค๋„ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

    :root {
        --textSize: 14px;
        --mainColor: #ffc600;
        --blur: 0px;
    }



    3. JS ์ž‘์„ฑํ•˜๊ธฐ

    ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์Šคํฌ๋ฆฝํŠธ ๋ถ€๋ถ„์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์šฐ์„  ๊ฐ ์˜ต์…˜(input)๋“ค์„ ์…€๋ ‰ํŒ…ํ•ฉ๋‹ˆ๋‹ค.

    const inputs = document.querySelectorAll(".option input");
    console.log(inputs);

    ์ฝ˜์†”์— [input, input, input]๊ณผ ๊ฐ™์ด ์ฐํ˜€๋‚˜์˜ค๋„ค์š”.
    ์–ผํ• ๋ด์„œ๋Š” ๋ฐฐ์—ด๊ฐ™์•„ ๋ณด์ด๋„ค์š”. [] ์•ˆ์— ๋“ค์–ด์žˆ๊ณ , ์ธ๋ฑ์Šค์™€ length๋„ ๊ฐ–๊ณ  ์žˆ์œผ๋‹ˆ๊นŒ์š”. ๊ทธ๋Ÿฌ๋‚˜....
    ๋‘๋‘ฅ. ์‚ฌ์‹ค ์–˜๋Š” NodeList์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค. (๋ฐฐ์—ด๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค, ๋ฐฐ์—ด๊ณผ๋Š”!) (*์ฐธ๊ณ )

    ์•„๋ฌด ๋ฐฐ์—ด์ด๋‚˜ ๋งŒ๋“  ๋‹ค์Œ ์ฝ˜์†”์— ์ฐ์–ด ๋น„๊ตํ•ด๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. __proto__๋กœ ์—ฐ๊ฒฐ๋œ ํ”„๋กœํ† ํƒ€์ž… ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๊ฐ๊ฐ NodeList, Array๋กœ ์„œ๋กœ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ฐฐ์—ด์€ ๋ฐฐ์—ด ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์•„ ์“ธ ์ˆ˜๊ฐ€ ์žˆ์–ด์š”(map, push, pop, filter, jon ๋“ฑ๋“ฑ!)
    ํ•˜์ง€๋งŒ NodeList๋Š” ๊ฐ–๊ณ  ์žˆ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋ช‡ ๊ฐœ ์—†๊ณ  ๊ฐ€๋‚œํ•ฉ๋‹ˆ๋‹ค(fotEach ์ •๋„...ใ… ใ… )
    ๊ทธ๋ž˜์„œ ํ•„์š” ์‹œ์—๋Š” ์ด NodeList๋ฅผ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์“ฐ๊ธฐ๋„ ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ๊ทธ๋ƒฅ forEach๋ฅผ ์“ธ ๊ฑฐ๋‹ˆ๊นŒ ํŒจ์Šคํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. forEach๋Š” IE 9๋ถ€ํ„ฐ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค! (*์ฐธ๊ณ )

    inputs.forEach(input => {
        console.log(input);
    });

    ์Œ... ๊ทธ๋Ÿผ ํฐํŠธ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ฐ”๊พธ๋ ค๋ฉด <input/>์— ๋‹ฌ๋ฆฐ ํ”„๋กœํผํ‹ฐ ์ค‘์— value ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋˜๊ฒ ๋„ค์š”. ๋ฉ”์ธ ์ปฌ๋Ÿฌ๊ฐ’์ด๋‚˜ blur๊ฐ’๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ value์—์„œ ๊ฐ€์ ธ์˜ค๋ฉด ๋  ๊ฑฐ ๊ฐ™๊ณ ์š”. ๊ทธ๋Ÿผ ์ด์ œ input์˜ ๊ฐ’์„ ๋ฐ”๊พธ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ๊ฒ ๋„ค์š”. ์šฐ์„ ์€ handleUpdate()๋ผ๋Š” ๋นˆ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ์—ฐ๊ฒฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค.

    const handleUpdate = function() {
        console.log(this.value);
    }
            
    inputs.forEach(input => {
        input.addEventListener("change", handleUpdate);
        input.addEventListener("mousemove", handleUpdate);
    });

    ์—ฌ๊ธฐ์„œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ change์™€ mousemove์ผ ๋•Œ ๋‹ฌ์•„์ค€ ์ด์œ ๋Š”, change๋Š” ๋งˆ์šฐ์Šค ์›€์ง์ž„์ด ๋๋‚œ ์ˆœ๊ฐ„๋งŒ ํฌ์ฐฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ range input์„ ๋“œ๋ž˜๊ทธํ•˜๋Š” '๋„์ค‘'์—๋Š” ๊ทธ ๊ฐ’์„ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— mousemove๋„ ํ•จ๊ป˜ ๋„ฃ์–ด์คฌ์Šต๋‹ˆ๋‹ค :)

    ์•„๋ฌดํŠผ ์ฝ˜์†”์„ ์‚ดํŽด๋ณด๋ฉด input์„ ์กฐ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค value๊ฐ€ ์ฐํ˜€๋‚˜์˜ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทผ๋ฐ ๊ทธ ๊ฐ’์ด ๊ทธ๋ƒฅ num(์ˆซ์ž)๋„ค์š”. CSS๋กœ ๋„ฃ์œผ๋ ค๋ฉด px ๋“ฑ์˜ ๋‹จ์œ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒŒ data-sizing์œผ๋กœ px์ด๋ž€ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋„ฃ์–ด์ค€ ์ด์œ ์ฃ ! ๋‹จ์œ„๋ฅผ ๋ฐ›์•„์˜ฌ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

    const handleUpdate = function() {
        const suffix = this.dataset.sizing || '';
    }

    ์—ฌ๊ธฐ์— ||๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ด์œ ๋Š”, ์ปฌ๋Ÿฌ๊ฐ’ ๊ฐ™์€ ๊ฒฝ์šฐ์—” data-sizing๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ undefined๊ฐ€ ๋œฐ ๊ฑฐ๊ณ , ๊ฒฐ๊ตญ #f1f1f1undefined๊ฐ™์ด ์ด์ƒํ•˜๊ฒŒ ๋‚˜์˜ค๊ฒ ์ฃ . ๊ทธ๋ž˜์„œ ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ์—” ๊ณต๋ฐฑ์ด ๋˜๋„๋ก ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

    ์ž, ๊ทธ๋Ÿผ ์ด์ œ ์ด ์œ ๋™์ ์ธ ๊ฐ’์„ --textSize์—๊ฒŒ ๋ฐ˜์˜์‹œ์ผœ ๋ณผ ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค.

    const handleUpdate = function() {
        const suffix = this.dataset.sizing || '';
        document.documentElement.style.setProperty('--textSize', this.value + suffix);
    }

    ์•„๋ฌด length input์„ ์›€์ง์ด๋ฉด ๊ทธ ๊ฐ’์— ๋”ฐ๋ผ ํฐํŠธ ์‚ฌ์ด์ฆˆ๊ฐ€ ์กฐ์ ˆ๋˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์šฐ์™€์•„์•™)
    ์—ฌ๊ธฐ์„œ document.documentElement๋Š” document์˜ ๋ฃจํŠธ ์š”์†Œ์ธ Element๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ๋ญ, ์‰ฝ๊ฒŒ ๋งํ•˜์ž๋ฉด <html>์ธ๋ฐ์š”, :root ์„ ํƒ์ž๋กœ ๋ฃจํŠธ ์š”์†Œ์—๋‹ค CSS๋ฅผ ์ž‘์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ ‡๊ฒŒ ๋ฃจํŠธ์š”์†Œ๋ฅผ ์…€๋ ‰ํŒ…ํ•œ ๊ฑฐ์ฃ . (*์ฐธ๊ณ )

    ๊ทธ ๋‹ค์Œ ๋‚˜์˜ค๋Š” style.setProperty()๋Š” CSS์†์„ฑ์„ ์žฌํ• ๋‹น์‹œํ‚ค๋Š” ๋ฐ ์“ฐ์ž…๋‹ˆ๋‹ค. (IE9+ ์ง€์›์ด๋ฉฐ IE8 ์ดํ•˜๋Š” setAttribute๋ฅผ ์จ์•ผํ•ฉ๋‹ˆ๋‹ค) (*์ฐธ๊ณ )
    ์ž, ์•„๋ž˜์— ๋‘ ์ฝ”๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค!

    button.style.setProperty ("background-color", "green");
    button.style.backgroundColor = "green";

    ๋ญ๊ฐ€ ๋‹ค๋ฅผ๊นŒ์š”? ์‚ฌ์‹ค, ์œ„ ๋‘ ์ฝ”๋“œ๋Š” ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค๋ฉด ์œ„์—๋Š” KEBAB-CASE๊ณ , ์•„๋ž˜๋Š” CAMEL-CASE๋ผ๋Š” ์ ์ด๊ฒ ๋„ค์š”. ์ €๋Š” JS๋กœ ์Šคํƒ€์ผ์„ ๋ฐ”๊พธ๋ ค๋ฉด ์ €๋ ‡๊ฒŒ ์นด๋ฉœ์ผ€์ด์Šค๋กœ ์จ์•ผํ•œ๋‹ค~๊ณ  ๋ฐฐ์› ์ง€๋งŒ ๊ทธ ์ด์œ ๋Š” ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค@.@
    ๊ทธ๋Ÿฐ๋ฐ ์ €๋ ‡๊ฒŒ ์นด๋ฉœ์ผ€์ด์Šค๋กœ ์จ์„œ ์Šคํƒ€์ผ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š”, style ๊ฐ์ฒด ๋•๋ถ„์ด๋”๋ผ๊ตฌ์š”! style๊ฐ์ฒด๊ฐ€ backgroundColor๋‚˜, color, borderBottom ๋“ฑ์˜ ์†์„ฑ์„ ๊ฐ–๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ ‘๊ทผํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฑฐ์ฃ .

    ํ—Œ๋ฐ ์šฐ๋ฆฌ๊ฐ€ ์“ฐ๋ ค๋Š” --textSize๋ผ๋Š” ์†์„ฑ์€ ๊ทธ๋ƒฅ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฉ๊ธˆ ์ฆ‰์„์—์„œ ๋ฟ… ๋งŒ๋“  ์†์„ฑ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ style ๊ฐ์ฒด์—๊ฒŒ ์ด๋Ÿฐ ์†์„ฑ์„ ๋ฌผ์–ด๋ด๋„ "๋จธ๋žญ" ์ด๋ž€ ๋Œ€๋‹ต๋งŒ ๋Œ์•„์˜ค๊ฒ ์ฃ ใ…‹ใ…‹ใ…‹ใ…‹ ๊ทธ๋ž˜์„œ ๋Œ€์‹  setProperty() ๋ฉ”์„œ๋“œ๋ฅผ ์จ์„œ ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” 3๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ–๋Š”๋ฐ, ๊ทธ๋ƒฅ ("{์Šคํƒ€์ผ ์ด๋ฆ„}", "{์Šคํƒ€์ผ ๋‚ด์šฉ}")๊ณผ ๊ฐ™์ด ๋‘ ๊ฐœ ์“ฐ๋ฉด ์ ์šฉ๋œ๋‹ค~!! ๋ผ๊ณ ๋งŒ ์šฐ์„  ์•Œ์•„๋‘ก์‹œ๋‹ค.
    ๊ทธ๋Ÿผ ์•„๊นŒ ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž ์ •์˜ ์†์„ฑ์—๋„ ๋ฐ˜์‘ํ•˜๊ฒŒ๋” ๋ฐ”๊ฟ€๊ฒŒ์š”.

    const handleUpdate = function() {
        const suffix = this.dataset.sizing || '';
        document.documentElement.style.setProperty(`${this.name}`, this.value + suffix);
    }
        

    ์งœ๋ผ์ง - ์ž˜ ์ ์šฉ๋˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค :D

    Codepen ๊ฒฐ๊ณผ๋ฌผ


    See the Pen Update CSS Variables With JS by NY KIM (@nykim_) on CodePen.



    ๋Œ“๊ธ€ 1