대표적인 Atomic CSS 라이브러리.
Tailwind CSS 공식 홈페이지에서 guildes/vite에 들어가면 vite에 tailwind를 설치할 수 있는 가이드를 제공해 주니 꼭 이걸 보고 따라 설치하도록 한다!
이 과정을 터미널로 따라서 작성하게 되면 Tailwind CSS 설치가 완료된다.
Tailwind CSS를 사용할 때 클래스 이름을 쉽게 병합할 수 있도록 도와주는 도구이다.
이 도구는 여러 개의 Tailwind CSS 클래스가 있을 때 중복된 클래스를 제거하고, 최적화된 결과를 생성해주게 된다. 주로 Tailwind CSS로 스타일링할 때, 긴 클래스 문자열을 깔끔하게 정리하는 데 유용하다.
만약,
<div class="bg-red-500 bg-red-500 text-white p-4">
Hello World
</div>
이와 같이 중복된 속성이 있는 클래스가 있다면,
twmerge를 사용하면 중복된 bg-red-500 클래스를 하나로 줄일 수 있게 된다.
이렇게 하면 CSS의 크기를 줄이고 코드 가독성을 높일 수 있다.
이런식으로 isActive && 'bg-blue-500 border-blue-500'active 한 상태일 때에는 ? css 변경을 할 수 있게 된다.
CSS-in-JS는 JavaScript 내에서 CSS 스타일을 작성하고 관리하는 기법을 의미한다.
이 방법은 전통적인 CSS 파일과는 다르게, 스타일을 JavaScript 코드 내에서 정의하고 컴포넌트와 함께 번들링하는 접근 방식이다.
CSS-in-JS는 컴포넌트 기반 스타일링을 더 쉽게 하고, 스타일의 범위를 컴포넌트로 한정하며, 스타일 충돌을 방지하는 등의 이점을 제공한다. 대표적으로 아래와 같은 CSS-in-JS 라이브러리가 있다.
npm i styled-components 를 터미널에 입력하고 설치하면 된다.
import styled from 'styled-components';
const HelloWorld = styled.h1`
font-size: 30px;
color: #ed4848;
text-decoration: line-through;
&:hover {
color: blue;
}
`;
const App = () => {
return (
<div>
<HelloWorld>Hello, World!</HelloWorld>
</div>
);
};
export default App;
styled.h1와 같이 생성할 태그를 .div, .h1 와 같이 입력하고 백틱을 사용해서 적용할 css를 적용하면 된다.
아직 인터넷 익스플로러 11이 강성한 사용량을 보이던 시절 인기가 높아진 CSS-in-JS 라이브러리이다.
styled-component는 IE 11을 지원하려면 폴리필(최신 자바스크립트 기능이 오래된 브라우저에서 동작하지 않는 문제를 해결하기 위해 사용되는 코드)을 사용해야 했지만, emotion은 별도의 폴리필 없이도 ie 11을 지원했다.
npm i @emotion/css 로 emotion을 설치하면 사용이 가능해진다.
import { css } from "@emotion/css";
const App = () => {
return (
<div>
<h1
className={css`
font-size: 30px;
color: #ed4848;
text-decoration: line-through;
&:hover{
color:blue;
}
`}
>
Hello, World!
</h1>
</div>
);
};
export default App;
제로 런 타임(Zero Run Time)이라는 개념이 새롭게 등장하게 되면서 최근에 급 부상하고 있는 라이브러리라고 한다.
제로 런 타임이란, 런 타임 오버헤드가 없는 CSS를 의미한다.
--> 조금 더 쉽게 말하면 스타일을 적용하는 데 있어서 런타임에 추가적인 자바스크립트 코드 실행이나 연산이 필요하지 않는 CSS를 의미한다.
그렇다면, 런타임 오버헤드란?
런타임 오버헤드란, 프로그램이 실행되는 동안 추가적인 연산이나 자원 소비를 의미한다.
--> 런타임 오버헤드가 발생하면 메모리 사용량이 증가하고, CPU 사용량이 증가하며, 응답 시간 지연이 된다는 성능적 단점이 발생하게 된다.
그럼 제로 런 타임이 아닌 것은 어떤데?
styled-components나 emotion 같은 라이브러리는 ‘컴포넌트가 렌더링 될 때’ 스타일을 생성하여 적용한다.
--> 이러한 라이브러리들은 컴포넌트가 렌더링 될 때마다 스타일을 생성하기 때문에 스타일을 동적으로 생성하거나 조건에 따라 스타일을 변경하는 경우에 유용하지만, 그에 따른 성능 비용이 따르게 된다.
npm i @vanilla-extract/css @vanilla-extract/vite-plugin 를 설치를 하면 된다.
styles.css.ts 폴더에
import { style } from "@vanilla-extract/css";
export const h1Style = style({
fontSize: "30px",
color: "#ed3838",
textDecoration: "line-through",
});
를 적용시키고,
import { h1Style } from "./vanila/styles.css.ts";
const App = () => {
return (
<div>
<h1 className={h1Style}>Hello, World!</h1>
</div>
);
};
export default App;
className={} 에 이렇게 적용시키면 된다.
스타일 충돌 없이 Tailwind CSS 클래스를 JS로 효율적으로 병합하는 유틸리티 함수이다.
위에서 twmerge를 살펴보면 된다!
말줄임표 처리를 손쉽게 도와주는 플러그인, 단, Tailwind 3.3 이상부터는 기본 내장되어 있어서 별도의 설치가 필요 없다.
이정도만 알아도 될 것 같다 !
구글 폰트를 적용하는 가장 간단한 방법은 @import 문법을 사용해서 CSS 파일에 추가하는 것이다.
이와 같이 Web에서는 <link>, @import로 폰트를 불러올 수 있게 된다.
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap");
body {
font-family: "Inter", sans-serif;
<Link>로 추가하는 방법은
index.html 폴더에서 <Link> 태그를 복사해 준 뒤,
css 속성을 정의해 주고,
이렇게 사용해주면 적용되는 것을 확인할 수 있다.
눈누 링크를 타고 들어가면 다양한 폰트를 확인할 수 있는데,
이 폰트를 사용하기 위해서는 이렇게 @font-face를 font.css에 추가해주면 된다.
그리고 이렇게 정의한 폰트를
.bagel {
font-family: 'BagelFatOne-Regular';
}
className으로 정의를 해두고,
이렇게 className에 bagel를 적게 되면 적용이 되는 것을 확인할 수 있다!
컴포넌트 코드를 각각 header, nav, main, footer의 4개의 컴포넌트를 생성해서 분리해봅시다.
export default function App() {
return (
<div>
<header>
<h1>내 웹사이트</h1>
</header>
<nav>
<ul>
<li>
<a href="#section1">소개</a>
</li>
<li>
<a href="#section2">서비스</a>
</li>
<li>
<a href="#section3">연락처</a>
</li>
</ul>
</nav>
<main>
<section id="section1">
<h2>소개</h2>
<p>여기에 소개 내용을 작성하세요.</p>
</section>
<section id="section2">
<h2>서비스</h2>
<p>여기에 제공하는 서비스 내용을 작성하세요.</p>
</section>
<section id="section3">
<h2>연락처</h2>
<p>여기에 연락처 정보를 작성하세요.</p>
</section>
</main>
<footer>
<p>© 2024 내 웹사이트. 모든 권리 보유.</p>
</footer>
</div>
);
}
components에 포함될 파일들은 꼭 src/components 폴더 안에 파일들을 위치하도록 해주는 것이 -> 관용이다!
위의 코드를 각각 컨포넌트로 분리하고
이렇게 App() 함수 안에 위치시키면 화면에 렌더링이 되는 것을 확인할 수 있다!
| 폼 이벤트 | onChange, onSubmit |
|---|---|
| 마우스 이벤트 | onClick, onMouseEnter, onMouseLeave |
| 키보드 이벤트 | onKeyDown, onKeyPress, onKeyUp |
| 포커스 이벤트 | onFocus, onBlur |
| 드래그 이벤트 | onDragStart, onDrageOver, onDrop |
| 터치 이벤트 | onTouchStart, onTouchMove, onTouchEnd |
export default function App() {
return (
<>
<div>App Components</div>
<button
onClick={() => {
alert('클릭');
}}
onMouseEnter={() => {
alert('마우스가 올라갔어요');
}}
onMouseDown={() => {
alert('마우스가 내려갔어요');
}}
>
클릭
</button>
</>
);
}
import React, { useState } from 'react';
const KeyboardExample = () => {
const [key, setKey] = useState('');
const handleKeyDown = (event) => {
setKey(event.key);
};
return (
<div>
<input type="text" onKeyDown={handleKeyDown} placeholder="Press any key" />
<p>Last key pressed: {key}</p>
</div>
);
};
export default KeyboardExample;
import React, { useState } from 'react';
const FocusExample = () => {
const [focused, setFocused] = useState(false);
return (
<div>
<input
type="text"
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
placeholder="Focus on me!"
/>
<p>{focused ? 'Input is focused' : 'Input is not focused'}</p>
</div>
);
};
export default FocusExample;
리액트에서 ‘props’는 컴포넌트 간에 데이터를 전달하는 방법이다.
‘props’는 부모 컴포넌트가 자식 컴포넌트에 전달하는 읽기 전용 데이터이다.
--> ‘props’는 컴포넌트가 상위 컴포넌트로부터 받는 입력값이라고 할 수 있으며, 컴포넌트는 이를 이용해 렌더링 결과를 동적으로 변경할 수 있다.
<Component 속성={값} />
연습 코드
import React from 'react';
const Greeting = ({ name } : { name : string } ) => {
return <h1>안녕하세요, {name}님!</h1>;
};
export default Greeting;
이렇게 Greeting 이라는 컴포넌트를 하나 생성했다.
App.tsx
import React from 'react';
import Greeting from './Greeting';
const App = () => {
const userName = "서연"; // 사용자 이름 정의
return (
<div>
<Greeting name={userName} /> {/* Greeting 컴포넌트에 name props 전달 */}
</div>
);
};
export default App;
App.tsx에서 Greeting을 불러온 뒤, name을 넘겨주면?
화면에 안녕하세요, 서연님! 이 뜨게 된다.
또한, name에서 받을 type은 string이기 때문에 string을 지정해주어야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>User Card</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<article class="card">
<div>
<img
class="card-img"
src="https://images.pexels.com/photos/158251/forest-the-sun-morning-tucholskie-158251.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
alt="background-pic"
/>
</div>
<div class="profile">
<img
class="prof-img"
src="https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
alt="profile-pic"
/>
<h3 class="alias">Sally Ramos</h3>
<p class="username">@sallytheramos</p>
<button>Follow</button>
</div>
</article>
</body>
</html>
문제
다음 주어진 HTML 코드와 CSS 코드가 있습니다. 해당 코드로 만들어지는 UI를 기본으로 하여 ProfileCard 컴포넌트를 만들어주세요. ProfileCard 컴포넌트는 배경 이미지, 유저 이미지, 유저 이름, 인스타 아이디를 Props로 전달 받도록 합니다.
이 문제를 해결하기 위해
ProfileCard 컴포넌트를 새로 생성해 주었다.
interface IProfileCardProps {
backgroundImage: string;
profileImage: string;
userName: string;
onFollow: string;
}
export default function ProfileCard({
backgroundImage,
profileImage,
userName,
onFollow,
}: IProfileCardProps) {
return (
<>
<article className="card">
<div>
<img
className="card-img"
src={backgroundImage}
alt="background-pic"
/>
</div>
<div className="profile">
<img className="prof-img" src={profileImage} alt="profile-pic" />
<h3 className="alias">{userName}</h3>
<p className="username">{onFollow}</p>
<button>Follow</button>
</div>
</article>
</>
);
}
여기서 interface로 받아올 것들의 타입을 정해주었고,
App.tsx에서 <ProfileCard/>를 불러와서 타입에 맞는 값을 넘겨주면 된다.
본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 3기 과정(B-log) 리뷰로 작성 되었습니다.
#유데미 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프 #React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정