📍 64일 차 1.21. 금. 온라인 강의
오늘은 CSS Module
, UI Framework
, CSS framework
, CSS-in-JS
, Styled-components
에 대해서 배우고 전반적인 사용 역사(?)에 대해서 배웠다. 기존에 사용하던 방식의 단점, 불편함 때문에 새로운 방식이 나왔고, 새로운 방식에서 생겨난 단점, 불편함을 통해 새로운 방식을 사용하고.. 이렇게 일련의 과정들을 배우니까 이해가 잘 됐다. 그리고 평소에 관심 있던 리팩토링에 대해서도 배웠는데 일련의 과정들을 보면서 리팩토링의 before / after
를 보며 가독성이 어떻게 증가되었는지 한번 살펴보자. 마지막에는 figma
의 조작법을 3가지정도만 작성했다. 한번 살펴보자.
❏ CSS Module
- 기존
CSS
의 단점: 하나의 스타일 sheet
가 여러 컴포넌트에 영향을 미친다.
- CSS module을 사용하면
class
, id
등 선택자가 겹칠 우려가 없음 (hash
값 사용)
- 스타일 충돌을 방지하고 코드를 격리하여 체계적으로 CSS 설계가 가능
- CSS module의 단점은 개발자가 스타일링을 직접 하나하나씩 해야 한다는 점이다.
| |
| import styles from "./app.module.css"; |
| |
| export default function App(){ |
| return( |
| <div> |
| <h1 className={ styles.title }>Pink Hello world</h1> // hash가 붙어있음 |
| <h1 className={ "title" }>Hello world</h1> // 그냥 title |
| </div> |
| ) |
| } |
| |
| |
| h1 { |
| font-size: 1.5rem; |
| } |
| |
| .title { |
| font-size: 2.5rem; |
| color: pink; |
| } |
❏ UI Framework
- 종류:
MUI(material UI)
, Ant design
- 장점은 이미 만들어져 있는 스타일이기 때문에 간편하고 쉽게 사용하기 좋다.
- 단점으로는 이미 다 만들어져 있기 때문에 styling의 학습 및 훈련이 필요한 초심자들에게는 비추천한다. 또한 해당 framework의 디자인 철학을 벗어나기 쉽지 않고, 컴포넌트들을 커스터마이징 하기 어려움
| |
| import "antd/dist/antd.css"; |
| import { Button } from "antd"; |
| |
| export default function App(){ |
| return( |
| <div> |
| <Button type="primary">Primary Button</Button> |
| <Button type="secondary">Secondary Button</Button> |
| <Button type="danger">Danger Button</Button> |
| </div> |
| ) |
| } |
❏ CSS Framework
- 종류:
Tailwind CSS
, w3.css
- 거대한 CSS 파일 하나를 가져오는 것
- 장점: 개발자가 따로 CSS 파일을 작성하지 않아도 HTML에 클래스만 적어주면 정해진 규칙대로 스타일링이 적용됨.
- 단점: CSS에 대한 이해력이 있어도 해당 framework를 사용하기 위한 학습을 또 다시 해야 함, 이미 다 만들어져 있어서 styling의 학습 및 훈련이 필요한 초심자들에게는 비추천
| |
| import { Helmet } from "react-helmet"; |
| |
| export default function App(){ |
| return( |
| <div> |
| <Helmet> // <head></head> |
| <link |
| rel="stylesheet" |
| href="https://www.w3schools.com/w3css/4/w3.css" |
| </> |
| </Helmet> |
| |
| <div className="w3-container w3-green"> |
| <h1>W3Schools Demo</h1> |
| <p>Lorem</p> |
| </div> |
| </div> |
| ) |
| } |
❏ CSS-in-JS
- 종류:
Styled-components
, emotion
- 따로 CSS 파일을 만들지 않고 JSX 파일 안에서 스타일링까지 해결 가능함
- 컴포넌트 재사용성이 쉬워짐
- JS 값을 props로 넘겨줘서 해당 JS 값에 의도된 styling을 바로 적용할 수 있다.
- class 이름에 hash값을 생성하여 선택자 이름이 겹칠 우려가 없다.
- 스타일링을 개발자가 직접 해야함
| import styled from "styled-components"; |
| |
| const Title = styled.hi` |
| font-size: 1.5rem; |
| text-align: center; |
| color: pink; |
| ` |
| |
| export default function App(){ |
| return <Title>Hello world</Title> |
| } |
❏ 기존 CSS 문법을 SCSS로 리팩토링하기
리팩토링하면서 느낀 것이지만 SCSS
로 작성했을 때의 장점은 코드를 계층적으로 작성할 수 있다는 것이었다. 따라서, 부모 - 자식 간의 관계를 코드를 통해 유추할 수 있었고, 동일한 선택자를 불필요하게 여러 번 사용할 필요 없이 &
으로 대체해서 사용하거나, 현재 선택자 이외에 다른 선택자만 사용하는 등 간편하게 사용하는 점이 좋았다.
| |
| .container { |
| padding: 10px; |
| background-color: lightgray; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| } |
| |
| .counter { |
| width: 100px; |
| height: 50px; |
| line-height: 50px; |
| font-size: 2rem; |
| border: 1px solid black; |
| border-radius: 8px; |
| text-align: center; |
| } |
| |
| .buttons-container { |
| margin-top: 20px; |
| } |
| |
| button { |
| color: white; |
| width: 80px; |
| height: 50px; |
| text-align: center; |
| border-radius: 10px; |
| } |
| |
| button + button { |
| margin-left: 10px; |
| } |
| |
| button.inc { |
| background-color: blue; |
| } |
| |
| button.dec { |
| background-color: red; |
| } |
| button:hover { |
| box-shadow: 10px 5px 5px gray; |
| } |
| |
| |
| |
| |
| .container { |
| padding: 10px; |
| background-color: lightgray; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| |
| .counter { |
| width: 100px; |
| height: 50px; |
| line-height: 50px; |
| font-size: 2rem; |
| border: 1px solid black; |
| border-radius: 8px; |
| text-align: center; |
| } |
| |
| .buttons-container { |
| margin-top: 20px; |
| |
| button { |
| color: white; |
| width: 80px; |
| height: 50px; |
| text-align: center; |
| border-radius: 10px; |
| |
| + button { |
| margin-left: 10px; |
| } |
| |
| &.inc { |
| background-color: blue; |
| } |
| |
| &.dec { |
| background-color: red; |
| } |
| |
| &:hover{ |
| box-shadow: 10px 5px 5px gray; |
| } |
| } |
| } |
| } |
❏ JavaScript template literal
- 문자열 안에서 JS 표현식을 사용할 수 있게 하는 문법이다.
string text ${expression} string text
| const string = "elice" |
| const message = `hello ${string}`; |
| console.log(message) |
| |
| const number = 12345 |
| const message = `hello ${number}`; |
| console.log(message) |
| |
| const boolean = true; |
| const message = `hello ${boolean}`; |
| console.log(message) |
| |
| const object = { a: "apple" }; |
| const message = `hello ${object}`; |
| console.log(message) |
| |
| const name = "Ted"; |
| const gender = "male"; |
| const message = `hello ${gender === "male" ? "Mr. " : "Mrs."}`; |
| console.log(message) |
❏ Styled-components
props
유무에 따른 styled-components
작성 방법
| |
| const Button = styled.button` |
| font-size: 32px; |
| margin: 1em; |
| padding: 0.25em 1em; |
| ` |
| |
| function App(){ |
| return <Button>Hello!</Button> |
| } |
| |
| |
| const Button = styled.button` |
| font-size: 32px; |
| margin: 1em; |
| padding: 0.25em 1em; |
| background: ${(props) => props.primary ? "pink" : "black"} |
| color: ${(props) => props.primary ? "white" : "green"} |
| ` |
| |
| function App(){ |
| return <Button primary>Hello!</Button> |
| } |
css
vs scss
vs styled-components
| // CSS |
| .name .red { |
| color: red; |
| } |
| |
| .name .blue { |
| color: blue; |
| } |
| |
| .name .green { |
| color: green; |
| } |
| |
| .name .child .yellow { |
| color: yellow; |
| } |
| |
| .name + .name { |
| color: purple; |
| } |
| |
| // SCSS: 중복된 선택자 제거 가능 |
| .name { |
| &.red { |
| color: red; |
| } |
| |
| &.blue { |
| color: blue; |
| } |
| |
| &.green { |
| color: green; |
| } |
| |
| .child { |
| .yellow { |
| color: yellow; |
| } |
| } |
| |
| + .name { /* 인접요소 연산자 */ |
| color: purple; |
| } |
| } |
| |
| // SCSS in styled components |
| const SCSSStyledDiv = styled.div` |
| background-color: orange; |
| color: white; |
| |
| div{ // SCSSStyledDiv 내부의 div태그의 bg color |
| background-color: red; |
| } |
| |
| .purple{ // SCSSStyledDiv 내부의 purple 클래스의 bg color |
| background-color: purple; |
| } |
| ` |
| |
| // Componennt Use Case |
| function Test(){ |
| return ( |
| <SCSSStyledDiv> |
| <div className={"purple"} /> |
| ) |
| } |
- style-components 로 CSS 수정하기
| // CSS |
| .container { |
| margin: 0 auto; |
| width: clamp(0px, 100%, 860px); |
| padding: 10px; |
| background-color: lightgray; |
| text-align: center; |
| } |
| |
| .count { |
| width: 128px; |
| margin: 0 auto; |
| margin-bottom: 16px; |
| padding: 16px; |
| border: 2px solid black; |
| border-radius: 16px; |
| font-size: 32px; |
| font-weight: 700; |
| } |
| |
| .button-wrapper { |
| margin-bottom: 16px; |
| } |
| |
| button { |
| padding: 16px; |
| background-color: blue; |
| color: white; |
| font-size: 32px; |
| border-radius: 16px; |
| } |
| |
| button:last-child { |
| background-color: red; |
| } |
| |
| button + button { |
| margin-left: 16px; |
| } |
| |
| button:hover { |
| box-shadow: 8px 4px 4px gray; |
| } |
| |
| // styled-components |
| const Container = styled.div` |
| margin: 0 auto; |
| width: clamp(0px, 100%, 860px); |
| padding: 10px; |
| background-color: lightgray; |
| text-align: center; |
| ` |
| |
| const Count = styled.div` |
| width: 128px; |
| margin: 0 auto; |
| margin-bottom: 16px; |
| padding: 16px; |
| border: 2px solid black; |
| border-radius: 16px; |
| font-size: 32px; |
| font-weight: 700; |
| ` |
| |
| const ButtonWrapper = styled.div` |
| margin-bottom: 16px; |
| ` |
| |
| const Button = styled.button` |
| padding: 16px; |
| background-color: ${(props) => props.bgColor }; |
| color: white; |
| font-size: 32px; |
| border-radius: 16px; |
| |
| & + & { // 둘중에 하나 사용하면 됨 |
| margin-left: 16px; |
| } |
| |
| + button { // 둘중에 하나 사용하면 됨 |
| margin-left: 16px; |
| } |
| |
| &:hover { |
| box-shadow: 8px 4px 4px gray; |
| } |
| ` |
❏ Figma
shift + scroll
:횡으로 scroll
- 좌측 Search: 컴포넌트 구조 확인 가능
- 마우스 커서로 컴포넌트 사이의 거리 확인 가능(
px
)
댓글