🌱SeSAC x CodingOn 웹 취업 부트캠프

[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 12주차 (1): React style

haeriyouu 2025. 1. 21. 14:31

Style 적용

💻 일반 CSS

- inline style 적용하기

export default function BasicCSS() {
  // object 따로 선언
  const childDiv = {
    backgroundColor: "pink",
    width: "100px",
    height: "100px",
    textAlign: "center",
    lineHeight: "100px",
  };
  return (
    <>
      <h3>스타일 적용 방법</h3>
      <ol>
        <li>인라인 스타일</li>
        <li>CSS 파일 만들어서 import</li>
        <li>.module.css 파일 만들어서 import</li>
        <li>styled-components 라이브러리 사용(설치 필요)</li>
        <li>SAAS 사용 (설치 필요)</li>
      </ol>
      <h4 style={{ color: "#888" }}>인라인 스타일로 적용</h4>
      <div style={{ backgroundColor: "#ddd" }}>
        <div style={childDiv}>안녕하세요!</div>
      </div>
      <h4>CSS 파일로 적용</h4>
      <div className="box1">
        <div>안녕하세요?</div>
      </div>
    </>
  );
}

 

- css-module

// ModuleCSS.jsx
import classNames from "classnames";
import style from "../style/style.module.css";
import Names from "classnames/bind";

export default function ModuleCSS() {
  const setting = Names.bind(style);

  return (
    <div className={style.container}>
      <h4>module.css 적용</h4>
      <div className={style.box2}>
        <div>안녕하삼</div>
      </div>
      <br />
      <div className={`${style.first} ${style.second}`}>
        클래스를 여러 개 지정하는 방법1(템플릿 리터럴)
      </div>
      {/* 
      [1,2,3,4,5].join("-") -> "1-2-3-4-5"
      ["first","second"].join"(" ") -> "first second"
      */}
      <div className={[style.first, style.second].join(" ")}>
        클래스를 여러 개 지정하는 방법2(배열과 join이용)
      </div>
      <div className={classNames(style.first, style.second)}>
        클래스를 여러 개 지정하는 방법3(classnames 모듈 설치)
      </div>
      <div className={setting("first", "second")}>
        classnames 모듈 사용 더 해보기
      </div>
    </div>
  );
}
/* style.module.css */

.container {
  border: 1px solid gray;
  padding: 0.5rem;
  margin: 1rem 0;
}

.box2 {
  background-color: palegreen;
}

.box2 div {
  background-color: paleturquoise;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-weight: 700;
}

.first {
  color: darkorange;
  font-size: 1.5rem;
}

.second {
  background-color: rgb(245, 224, 255);
  border: 1px solid salmon;
}

💻 Styled Components

npm install styled-components
import styled, { keyframes } from "styled-components";

const StyledContainer = styled.div`
  border: 1px solid gray;
  padding: 0.5rem;
  margin: 1rem 0;
`;

const H4Title = styled.h4`
  background-color: yellowgreen;

  /* 반응형 설정하기 */
  /* 세로방향 */
  @media screen and (max-width: 780px) and (orientation: portrait) {
    color: green;
  }
  /* 가로방향 */
  @media screen and (max-width: 780px) and (orientation: landscape) {
    color: red;
  }
`;

const ParentDiv = styled.div`
  background-color: #444;
  display: flex;
`;

const rotate = keyframes`
    0%{
        transform: rotate(0);
    }
    50%{
        transform:rotate(180deg);
        background-color: aliceblue;
    }
    100%{
        transform: rotate(360deg);
    }
`;

// props 사용, hover, animation
const Child = styled.span`
  color: red;

  &:hover {
    cursor: pointer;
    /* color: wheat; */
    color: ${(props) => (props.color ? props.color : "wheat")};
    background-color: ${(props) => (props.bg ? props.bg : "yellow")};
    /* animation */
    animation: ${rotate} 1s linear infinite;
  }
`;

export default function StyledComponents() {
  return (
    <StyledContainer>
      <H4Title>Styled Components 이용</H4Title>
      <ParentDiv>
        <Child>element1</Child>
        <Child color="blue" bg="skyblue">
          element2
        </Child>
        <Child>element3</Child>
      </ParentDiv>
    </StyledContainer>
  );
}

💻 SASS

npm install sass
// Sass.jsx

import "../style/Sass.scss";
import img1 from "../assets/hachi.jpg";

export default function Sass() {
  return (
    <>
      <h4>SASS 사용(.scss)</h4>
      <div className="div1">
        <div className="div2">
          <div className="div3"></div>
        </div>
        <button className="btn orangered">Button1</button>
        <button className="btn btn--opacity">Button2</button>
        <button className="btn btn--blue">Button3</button>
      </div>

      {/* mixin 사용 해 보기 */}
      <div className="container">
        <div className="box1"></div>
        <div className="box1"></div>
        <div className="box1"></div>

        <p className="circle"></p>
        <p className="circle"></p>
        <p className="circle"></p>

        <div className="box2">1</div>
        <div className="box2">2</div>
        <div className="box2">3</div>
        <div className="box2">4</div>
      </div>

      {/* image 불러오기 */}
      <h2>이미지 가져오기</h2>
      <h4>1. src 폴더 내부의 이미지 가져오기</h4>
      <h5>경로명으로 가져오기(상대경로)</h5>
      <img
        src="../assets/hachi.jpg"
        alt="src 내부의 사진은 경로명으로 바로 접근 불가능합니다."
      />

      <h5>import 후 가져오기</h5>
      <img src={img1} alt="import 후 가지고 오기" />

      <h4>1. public 폴더 내부의 이미지 가져오기</h4>
      <img
        src="/images/hachi.jpg"
        alt="public 폴더 내부에서는 경로명으로 접근 가능. 단, public 폴더 /이후로 접근"
      />
      <img
        src={process.env.PUBLIC_URL + "/images/hachi.jpg"}
        alt="process.env.PUBLIC_URL로 접근하면 조금 더 안전 함"
      />
      <h5>CSS에서 background-image 속성으로 접근하기</h5>
      <div className="src-img img-test"></div>

      <h4>실습문제</h4>
      <div className="practice">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>
    </>
  );
}
/* Sass.scss */

@import "util";

h4 {
  color: gray;
}

.div1 {
  width: 200px;
  height: 200px;
  background-color: $color-red;
  > .div2 {
    width: 50%;
    height: 50%;
    background-color: $color-orange;
    .div3 {
      width: 50%;
      height: 50%;
      background-color: $color-yellow;
    }
  }

  .btn {
    // .btn 클래스의 공통 속성
    display: inline-block;
    transition: 0.4s;
    width: 33%;
    height: 40px;
    color: white;
    line-height: 40px;
    text-align: center;
    font-size: 10px;

    // .btn.orangered
    &.orangered {
      background-color: orangered;
    }

    // .btn--opacity
    &--opacity {
      background-color: $color-blue;
      opacity: 0.5;
      &:hover {
        opacity: 0.8;
      }
    }

    // .btn--blue
    &--blue {
      background-color: $color-blue;
    }
    &:hover {
      cursor: pointer;
      font-weight: 700;
    }
  }
}

.container {
  width: 100%;
  background-color: antiquewhite;
  .box1 {
    height: 50px;
    background-color: $color-orange;
    // &:nth-child(1) {
    //   width: 100px;
    // }
    // &:nth-child(2) {
    //   width: 120px;
    // }
    // &:nth-child(3) {
    //   width: 140px;
    // }
    @for $i from 1 through 3 {
      // #{}: 보간
      // 문자 사이에 변수를 넣거나, 연산이 아닌 곳에 값을 넣을 때 사용용
      &:nth-child(#{$i}) {
        // width: (80px + 20px * $i);
        // border: 1px solid $color-blue;
        @include box;
      }
    }
  }

  .circle {
    // @include circle(red, 0.5);
    &:nth-child(4) {
      @include circle(blue, 0.5);
    }
    &:nth-child(5) {
      @include circle(dodgerblue, 0.5);
    }
    &:nth-child(6) {
      @include circle(rgb(166, 166, 255), 0.5);
    }

    $circleBgColors: (blue, dodgerblue, #a6a6ff);
    @each $el in $circleBgColors {
      // index(): SASS에서 기본적으로 제공하는 함수
      // - index(list, value)
      // - 특정 list에서 value의 index를 반환하는 함수
      // - index는 1번부터 시작
      $index: index($circleBgColors, $el);
      &:nth-child(#{$index + 3}) {
        @include circle($el, 1.2 - 0.2 * $index);
        // @include circle(); // error
      }
    }
  }
  .box2 {
    @include box2();

    &:nth-of-type(4) {
      @include box2(yellow, 20px, navy);
    }
    &:nth-of-type(5) {
      @include box2(orangered, 30px, black);
    }
  }
}

.img-test {
  width: 100px;
  height: 100px;
  border: 1px solid $color-blue;

  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  &.src-img {
    background-image: url("../assets/hachi.jpg");
  }

  &.public-img {
    background-image: url("http://localhost:3000/images/hachi.jpg");
  }
}

.practice {
  display: flex;
  justify-content: space-evenly;
  div {
    width: 200px;
    height: 300px;
    background-color: #7f8ff5;
    margin: 50px 0;
    border-radius: 10%;

    background-position: center;
    background-repeat: no-repeat;
    background-size: contain;
    cursor: pointer;
    box-shadow: $boxShadow;
    @for $i from 1 through 4 {
      &:nth-child(#{$i}) {
        background-image: url("../assets/practice#{$i}.png");
      }
    }
  }
}

📍 @mixin

- CSS 스타일 시트에서 재사용 가능한 스타일 그룹을 정의하는 기능.

- 반복적으로 사용되는 CSS 코드를 효율적으로 관리하고 재사용할 수 있게 해준다.

- 장점: 

  1. 코드 재사용: 반복되는 스타일을 한 번만 정의하고 여러 곳에서 재사용할 수 있음

  2. 유지보수 용이성: 공통 스타일을 한 곳에서 관리할 수 있음

  3. 반응형 디자인: 미디어 쿼리등을 믹스인으로 정의하여 반응형 스타일을 쉽게 적용 할 수 있음 

/* _util.scss */

$color-red: #d04848;
$color-orange: #f3b95f;
$color-yellow: #fde767;
$color-green: #96ceb4;
$color-blue: #6895d2;

$boxShadow: 2px 2px 6px rgba(0, 0, 0, 0.152);
// 변수같은 것은 관리를 위해 하나의 파일에서 관리하는 것이 좋다.

@mixin box {
  width: 100px;
  height: 100px;
  border: 1px solid black;
  display: inline-block;
  box-sizing: border-box;
}

@mixin circle($circleColor, $circleOpacity) {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 1px solid black;
  display: inline-block;
  background-color: $circleColor;
  opacity: $circleOpacity;
}

@mixin box2(
  $squareBgColor: $color-red,
  $squareFontSize: 15px,
  $squareColor: gray
) {
  @include box();
  background-color: $squareBgColor;
  line-height: 100px;
  text-align: center;
  font-size: $squareFontSize;
  color: $squareColor;
  @if $squareBgColor==$color-red {
    border-radius: 50%;
  } @else if $squareColor==black {
    border-radius: 25%;
  } @else {
    border-radius: 0;
  }
}