๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
ํ”„๋ก ํŠธ์—”๋“œ/React

Sass

by alswlfl 2022. 12. 6.

โญ๏ธ css ์ „์ฒ˜๋ฆฌ๊ธฐ(Pre-Processor)

: ๋ชจ๋“ˆ๋ณ„๋กœ ํŠน๋ณ„ํ•œ Syntax๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ์—ฌ๊ธฐ์— mixin, nesting selector, ์ƒ์† ๋“ฑ ํ”„๋กœ๊ทธ๋ž˜๋จธ์ ์ธ ์š”์†Œ๋ฅผ ์ ‘๋ชฉํ•ด ๋ฐฉ๋Œ€ํ•ด์ง€๋Š” CSS ๋ฌธ์„œ์˜ ์–‘์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ํ†ตํ•ฉ์ ์ธ ์–ธ์–ด

→ CSS ์ „์ฒ˜๋ฆฌ๊ธฐ ์ž์ฒด๋งŒ์œผ๋กœ๋Š” ์›น ์„œ๋ฒ„๊ฐ€ ์ธ์‹ ๋ชปํ•˜๋ฏ€๋กœ, ๊ฐ CSS์ „์ฒ˜๋ฆฌ๊ธฐ์— ๋งž๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CSS๋ฌธ์„œ๋กœ ๋ณ€ํ™˜ํ•ด์•ผํ•จ

์žฅ์ 

  1. ์žฌ์‚ฌ์šฉ์„ฑ: ๊ณตํ†ต ์š”์†Œ ๋˜๋Š” ๋ฐ˜๋ณต์ ์ธ ํ•ญ๋ชฉ์„ ๋ณ€์ˆ˜ ๋˜๋Š” ํ•จ์ˆ˜๋กœ ๋Œ€์ฒด
  2. ์‹œ๊ฐ„์  ๋น„์šฉ ๊ฐ์†Œ: ์ž„์˜ ํ•จ์ˆ˜ ๋ฐ Built-in ํ•จ์ˆ˜๋กœ ์ธํ•ด ๊ฐœ๋ฐœ ์‹œ๊ฐ„์  ๋น„์šฉ ์ ˆ์•ฝ
  3. ์œ ์ง€๊ด€๋ฆฌ: ์ค‘์ฒฉ, ์ƒ์†๊ณผ ๊ฐ™์€ ์š”์†Œ๋กœ ์ธํ•ด ๊ตฌ์กฐํ™”๋œ ์ฝ”๋“œ๋กœ ์œ ์ง€ ๋ฐ ๊ด€๋ฆฌ ์šฉ์ด

https://kdydesign.github.io/2019/05/12/css-preprocessor/

 

CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(Pre-Processor) ๋ฐฐ์šฐ๊ธฐ!

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” Sass, Less, Stylus์™€ ๊ฐ™์€ CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(CSS Pre-Processor)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž. CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(CSS Preprocessor)๋Š” CSS ์ž‘์„ฑ ๋ชจ๋“ˆ๋ณ„๋กœ ํŠน๋ณ„ํ•œ Syntax๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ์—ฌ๊ธฐ์— ๋ฏน์Šค์ธ(mixin), ์ค‘์ฒฉ ์…€๋ ‰

kdydesign.github.io


Sass (Syntactically Awesome Style Sheets): ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋ฉ‹์ง„ ์Šคํƒ€์ผ์‹œํŠธ

CSS Pre-Processor

  1. ๋ณต์žกํ•œ ์ž‘์—… ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
  2. ์ฝ”๋“œ์˜ ์žฌํ™œ์šฉ์„ฑ ๋†’์—ฌ์คŒ
  3. ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ ๋†’์—ฌ์ฃผ์–ด ์œ ์ง€๋ณด์ˆ˜ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ

Sass์—์„œ๋Š” .scss ์™€ .sass ๋‘ ๊ฐ€์ง€์˜ ํ™•์žฅ์ž๋ฅผ ์ง€์›ํ•จ → ๋ฌธ๋ฒ•์ด ๋‹ค๋ฆ„

ex) ๋งˆ์ง€๋ง‰์— ์ฝœ๋ก (;)์„ ๋ถ™์ด๋А๋ƒ ์•ˆ๋ถ™์ด๋А๋ƒ, ๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ๋А๋ƒ์— ๋Œ€ํ•œ ์—ฌ๋ถ€

 

sass

$font-stack: Helvetica, san-serif
$primary-color: #333

body
	font: 100% $font-stack
    	color: $primary-color

scss

$font-stack: Helvetica, san-serif;
$primary-color: #333;

body{
	font: 100% $font-stack
    	color: $primary-color
}

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

$ cd styling-with-sass
$ yarn add node-sass

Sass๋ฅผ CSS๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ์—ญํ• 

ex)

$blue: #228be6; // ์ฃผ์„ ์„ ์–ธ

.Button {
  display: inline-flex;
  color: white;
  font-weight: bold;
  outline: none;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  height: 2.25rem;
  padding-left: 1rem;
  padding-right: 1rem;
  font-size: 1rem;

  background: $blue; // ์ฃผ์„ ์‚ฌ์šฉ
  &:hover {
    background: lighten($blue, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
  }

  &:active {
    background: darken($blue, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
  }
}
  • ์Šคํƒ€์ผ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ → $blue: #228be6
  • ์ƒ‰์ƒ์„ ๋” ๋ฐ๊ฒŒํ•˜๊ฑฐ๋‚˜ ์–ด๋‘ก๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜ → lighten() ๋˜๋Š” darken()

๋ฒ„ํŠผ ์‚ฌ์ด์ฆˆ ์กฐ์ •

๋ฒ„ํŠผ ํฌ๊ธฐ์— large, medium, small ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„

  • className์— CSS ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋™์ ์œผ๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ๋ฒ• 
    1. className={['Button',size].join(' ')}
    2. className={`Button ${size}`}
    3. classnames ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ(๊ฐ€์žฅ ํŽธํ•จ) → ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง ์‹œ, ํ•จ์ˆ˜์˜ ์ธ์ž์— ๋ฌธ์ž์—ด, ๋ฐฐ์—ด, ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์†์‰ฝ๊ฒŒ ๋ฌธ์ž์—ด ์กฐํ•ฉ ๊ฐ€๋Šฅ
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
classNames(['foo', 'bar']); // => 'foo bar'

// ๋™์‹œ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ํƒ€์ž…์œผ๋กœ ๋ฐ›์•„์˜ฌ ์ˆ˜ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// false, null, 0, undefined ๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

classname๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

yarn add classnames
$blue: #228be6; // ์ฃผ์„ ์„ ์–ธ

.Button {
  display: inline-flex;
  color: white;
  font-weight: bold;
  outline: none;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  //์‚ฌ์ด์ฆˆ ๊ด€๋ฆฌ
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }
  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  background: $blue; // ์ฃผ์„ ์‚ฌ์šฉ
  &:hover {
    background: lighten($blue, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
  }

  &:active {
    background: darken($blue, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
  }
}

โญ๏ธ &์˜ ์˜๋ฏธ๋Š” ์ƒ์œ„์— ์Šคํƒ€์ผ ์ ์šฉ

.Button {
	&. large {
    
    }
}
/*๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์€*/
.Button.large {
}

โญ๏ธ ์—ฌ๋ฐฑ ์„ค์ •: & + &

  & + & {
    margin-left: 1rem;
  }

๋ฒ„ํŠผ ์ƒ‰์ƒ ์„ค์ •

https://yeun.github.io/open-color/

 

Open Color

Color scheme for UI design

yeun.github.io

$blue: #228be6; // ์ฃผ์„ ์„ ์–ธ
$gray: #495057;
$pink: #f06595;

.Button {
  display: inline-flex;
  color: white;
  font-weight: bold;
  outline: none;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  //์‚ฌ์ด์ฆˆ ๊ด€๋ฆฌ
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }
  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  //์ƒ‰์ƒ ๊ด€๋ฆฌ
  &.blue {
    background: $blue;
    &:hover {
      background: lighten($blue, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
    }
    &:active {
      background: darken($blue, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
    }
  }
  &.gray {
    background: $gray;
    &:hover {
      background: lighten($gray, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
    }
    &:active {
      background: darken($gray, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
    }
  }
  &.pink {
    background: $pink;
    &:hover {
      background: lighten($pink, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
    }
    &:active {
      background: darken($pink, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
    }
  }

  & + & {
    margin-left: 1rem;
  }
}

โญ๏ธ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋Š” mixin ๊ธฐ๋Šฅ ์‚ฌ์šฉํ•˜์—ฌ ์žฌ์‚ฌ์šฉ

$blue: #228be6; // ์ฃผ์„ ์„ ์–ธ
$gray: #495057;
$pink: #f06595;

@mixin button-color($color) {
  background: $color;
  &:hover {
    background: lighten($color, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
  }
  &:active {
    background: darken($color, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
  }
}
.Button {
  display: inline-flex;
  color: white;
  font-weight: bold;
  outline: none;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  //์‚ฌ์ด์ฆˆ ๊ด€๋ฆฌ
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }
  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  //์ƒ‰์ƒ ๊ด€๋ฆฌ
  &.blue {
    @include button-color($blue);
  }
  &.gray {
    @include button-color($gray);
  }
  &.pink {
    @include button-color($pink);
  }

  & + & {
    margin-left: 1rem;
  }
}

outline ์˜ต์…˜ ๋งŒ๋“ค๊ธฐ

function Button({ children, size, color, outline }) {
  return (
    <button className={classNames("Button", size, color, { outline })}>
      {children}
    </button>
  );
}

props๋กœ ๋ฐ›์•„์™€ ๊ฐ์ฒด ์•ˆ์— ์ง‘์–ด ๋„ฃ์€ ๋‹ค์Œ classNames()์— ํฌํ•จ ์‹œ์ผœ์ฃผ๋ฉด, outline๊ฐ’์ด true์ผ ๋•Œ๋งŒ, button์— css์ ์šฉ

@mixin button-color($color) {
  background: $color;
  &:hover {
    background: lighten($color, 10%); // ์ƒ‰์ƒ 10% ๋ฐ๊ฒŒ
  }
  &:active {
    background: darken($color, 10%); // ์ƒ‰์ƒ 10% ์–ด๋‘ก๊ฒŒ
  }
  &.outline {
    color: $color;
    background: none;
    border: 1px solid $color;
    &:hover {
      background: $color;
      color: white;
    }
  }
}

์ „์ฒด ๋„ˆ๋น„ ์ฐจ์ง€ํ•˜๋Š” ์˜ต์…˜: fullWidth

  &.fullWidth {
    width: 100%;
    justify-content: center;
    & + & {
      margin-left: 0;
      margin-top: 1rem;
    }
  }
function Button({ children, size, color, outline, fullWidth }) {
  return (
    <button
      className={classNames("Button", size, color, { outline, fullWidth })}
    >
      {children}
    </button>
  );
}

...rest props ์ „๋‹ฌ

→ ์ปดํฌ๋„ŒํŠธ์— onClick ์„ค์ •ํ•˜๊ฑฐ๋‚˜ onMouseMove ๋“ฑ ์ด๋ฒคํŠธ ๊ด€๋ฆฌ ์‹œ ์‚ฌ์šฉ

spread ์™€ rest ์‚ฌ์šฉ

function Button({ children, size, color, outline, fullWidth, ...rest }) {
  return (
    <button
      className={classNames("Button", size, color, { outline, fullWidth })}
      {...rest}
    >
      {children}
    </button>
  );
}

...rest ์‚ฌ์šฉํ•˜์—ฌ ์ง€์ •ํ•œ props ์ œ์™ธํ•œ ๊ฐ’๋“ค์€ rest ๊ฐ์ฒด์— ๋ชจ์•„์ฃผ๊ณ , {...rest} ํ•ด์ฃผ๋ฉด rest์•ˆ์— ์žˆ๋Š” ๊ฐ์ฒด ์•ˆ์— ์žˆ๋Š” ๊ฐ’๋“ค์„ ๋ชจ๋‘ ํƒœ๊ทธ์— ์„ค์ • ํ•ด์คŒ

 


โ—๏ธ px vs em vs rem

px: ๊ณ ์ •๋œ ์ ˆ๋Œ“๊ฐ’ ๋‹จ์œ„

em, rem: ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ๋‹จ์œ„ → ๊ฐ€๋ณ€๋‹จ์œ„๋กœ์„œ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ px๋กœ ๋ณ€ํ™˜๋จ

 

em: ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ์—์„œ ์ง€์ •๋œ ๊ฐ’ ๊ธฐ์ค€์œผ๋กœ px๋กœ ๋ฐ”๋€Œ์–ด ํ™”๋ฉด์— ํ‘œ์‹œ๋จ 

→ ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ์— ์„ค์ •๋œ ํฌ๊ธฐ ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ, ์ƒ์œ„ ์š”์†Œ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ๊ธฐ์ค€์ด ๋จ

rem: ์ตœ์ƒ์œ„ ์—˜๋ฆฌ๋จผํŠธ์—์„œ ์ง€์ •๋œ ๊ฐ’ ๊ธฐ์ค€์œผ๋กœ ๋ณ€ํ™˜๋จ(๋ณดํ†ต HTML tag์—์„œ ์ง€์ •๋œ ์‚ฌ์ด์ฆˆ ๊ธฐ์ค€)

→ ๋ณ„๋„์˜ ์‚ฌ์ด์ฆˆ ์„ค์ •์„ ์•ˆํ•œ ๊ฒฝ์šฐ ๊ฐ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ค์ •๋œ ๊ฐ’์„ ์ƒ์† ๋ฐ›์Œ

 

์ฆ‰, rem์€ ๊ธฐ์ค€์ด ๋˜๋Š” ํฌ๊ธฐ ํ•˜๋‚˜๋กœ ๊ณ ์ •๋˜์–ด ์žˆ๊ณ , em์€ ๊ฐ™์€ ์—˜๋ฆฌ๋จผํŠธ๋Š” ์–ด๋””์„œ๋ผ๋„ ๊ธฐ์ค€์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์–ด ํฌ๊ธฐ ์˜ˆ์ธก ์–ด๋ ค์›€

em๊ณผ rem

https://monkeydeveloper.tistory.com/entry/CSS-px-em-rem-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90

 

[CSS] px | em | rem ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด์ž

px | em | rem ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด์ž px์€ ๊ณ ์ •๋œ ์ ˆ๋Œ€๊ฐ’์˜ ๋‹จ์œ„๋ฉฐ, em๊ณผ remํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. ๊ณ ์ •๋œ px๊ณผ ๋‹ฌ๋ฆฌ, ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” em๊ณผ rem์˜ ์žฅ์ ์€ ๋ฌด์—‡์ด๋ฉฐ, ์–ด๋–ค ๊ฒฝ์šฐ์— ๊ฐ๊ฐ์˜ ๋‹จ์œ„๋ฅผ

monkeydeveloper.tistory.com