Emotion 라이브러리를 사용하여 CSS-in-JS를 React 앱에 적용하는 방법을 알아보세요.

소개
이 튜토리얼에서는 CSS-in-JS를 사용하는 예제로 Emotion 라이브러리로 React 앱의 스타일을 지정합니다.
3개의 호텔 카드가 포함된 여행 앱의 스타일을 지정할 것입니다. 각 카드에는 기본 이미지, 제목, 설명 및 사용자가 호텔에 대한 자세한 정보를 보거나 객실을 예약할 수 있는 버튼이 포함되어 있습니다.
Emotion을 설정하고 CSS-in-JS 구문을 사용하여 기존 React 앱에 스타일을 적용합니다.
최종 제품은 다음과 같습니다.

현재 React 앱은 CSS-in-JS를 React 앱에 적용하는 방법을 배우는 데 중점을 두고 있으므로 정적 웹사이트일 뿐입니다.
시작하자!
시작 코드 다운로드:
https://github.com/kibetamos/Starter-code

프로젝트 설정
시작 코드 폴더의 루트에서 다음 명령을 실행하여 필요한 종속 항목을 설치합니다.

npm install


다음으로 다음 명령을 사용하여 앱을 시작합니다.

npm start


반응 애플리케이션이므로 브라우저의 localhost:3000에서 스타일이 지정되지 않은 다음과 같은 React 앱을 볼 수 있습니다.

위의 응용 프로그램에는 로고가 너무 크고 카드가 서로 수직으로 놓여 있는 것과 같은 몇 가지 문제가 있습니다. 이제 Emotion 라이브러리를 사용하여 CSS-in-JS로 React 앱의 스타일을 지정할 수 있습니다.

패키지 설치
우리는 Emotion을 사용하는 두 가지 주요 방법이 있습니다.
The_ @emotion/css_ 패키지는 프레임워크에 구애받지 않으며 Emotion을 사용하는 가장 간단한 방법입니다. 비 React 앱으로 Emotion을 사용하는 것이 권장되는 방법입니다.
React 앱용 Emotion 라이브러리를 설치하려면 터미널에서 다음 명령을 실행하십시오.

npm i @emotion/react


패키지 설치가 완료되면 다음 명령을 사용하여 서버를 시작합니다.

npm start


이제 CSS-in-JS를 사용하여 Emotion 라이브러리로 앱의 스타일을 지정할 준비가 되었습니다!

CSS 소품
css 소품을 사용하면 요소의 스타일을 지정할 수 있습니다. , 로고 및 모든 호텔 카드를 포함하는 의 스타일을 지정하여 시연할 수 있는 개체 또는 태그가 지정된 템플릿 리터럴을 지원할 수 있습니다. 각 카드는 사용자가 자세히 알아보거나 예약하기 위해 클릭할 수 있는 버튼과 함께 호텔 배열의 기본 이미지, 제목 및 설명으로 구성됩니다.

starter-code/src/App.js 파일의 상단에서 감정에서 CSS 소품을 가져옵니다. Create React App 4를 사용할 때 파일 상단에/** @jsxImportSource @emotion/react */주석을 포함합니다. 이 주석은 Babel에 자동 런타임 가져오기를 사용자 지정하도록 알립니다.

/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

이제 css 소품을 사용하여 태그 스타일을 지정할 수 있습니다.
아래 return 문에서 , 로고 및 컨테이너를 복사하여 App.js의 현재 , 및 요소 위에 붙여넣습니다.

function App() {
  ...
  return (
    <main
      css={{
        color: "#03045e",
        background: "#caf0f8",
        height: "1200px",
        fontFamily: "helvetica",
      }}
    >
      <img
        src={logo}
        alt="logo"
        css={css`
          display: absolute;
          margin-top: 15px;
          margin-left: 15px;
          height: 100px;
          width: 100px;
        `}
      />
      <div
        css={css`
          display: flex;
          justify-content: center;
          align-items: center;
          gap: 15px;
          padding: 20px;
          @media (max-width: 900px) {
            display: grid;
          }
        `}
      >

      </div>
    </main>
  );
}

export default App;

결과입니다


*객체 스타일 *

요소는 스타일 개체 스타일 및 값이 있는 개체를 사용합니다. 일반 CSS처럼 kebab-case로 CSS 속성을 작성하는 대신 camelCase로 작성합니다. 공지 속성은 쉼표로 구분됩니다. 개체 스타일은 문자열 스타일과 같은 CSS 호출이 필요하지 않지만 개체 스타일은 스타일이 지정된 구성 요소와 함께 사용할 수도 있기 때문에 특히 유용합니다.

<main
  css={{
    color: "#03045e",
    background: "#caf0f8",
    height: "1200px",
    fontFamily: "helvetica",
  }}
>
  ...
</main>

문자열 스타일
css 소품은 또한 태그가 있는 템플릿 리터럴을 사용하여 및 요소의 스타일을 지정했습니다. 템플릿 리터럴은 백틱으로 묶입니다( ). Notice the css properties are written in kebab-case and separated by a semicolon.
<img
  src={logo}
  alt="logo"
  css={css`
    display: absolute;
    margin-top: 15px;
    margin-left: 15px;
    height: 100px;
    width: 100px;
  `}
/>

Styled Components

The Emotion library has a package called @emotion/styled, which gives us access to styled, that allows you to create components that have styles attached to them. It is similar to css prop except it is called with an HTML tag or React component.

To install the styled package from the Emotion library, stop the server, and run the following command:

npm i @emotion/styled

In the empty starter-code/src/styles.js file, Create a CardWrapper component that will style each individual hotel card in the hotels array found in App.js.

At the top of the styles.js file, import styled from the @emotion/styled package. Beneath that, create a CardWrapper component that will be used to style each hotel’s container

.
import styled from "@emotion/styled";

export const CardWrapper = styled.div`
  width: 250px;
  height: 325px;
  background: #fff;
  border-radius: 15px;
  padding-bottom: 5px;
  @media (max-width: 900px) {
    width: 400px;
  }
`;

Note that you are exporting the CardWrapper component so that it can be used it in the App.js file.

At the top of the App.js file, import CardWrapper from styles.js. Next, change the container

for each hotel to a CardWrapper component.
import { CardWrapper } from "./styles.js";

{hotels.map((hotel) => {
    return (
    <CardWrapper key={hotel.id}>
        <img src={hotel.src} alt={hotel.alt} />
        <div>
            <h2>{hotel.title}</h2>
            <h3>{hotel.description}</h3>
        </div>
        <div>
            <button>Details</button>
            <button>Book</button>
        </div>
    </CardWrapper>
    );
})}

This is the result:


Now, build out styled components to be used for each hotel’s image, text container, title, description, buttons container, and buttons in styles.js. This is also an excellent time to experiment with your own styling.

// styles.js
...

export const CardWrapper = styled.div`
  ...
`;

export const ImageWrapper = styled.img`
  object-fit: cover;
  width: 100%;
  height: 60%;
  border-radius: 15px 15px 0 0;
`;

export const TextWrapper = styled.div`
  padding: 10px;
  height: 50px;
`;

export const TitleWrapper = styled.h2`
  margin: 0;
  font-size: 20px;
`;

export const DescriptionWrapper = styled.h3`
  margin-top: 5px;
  font-size: 14px;
  color: #023e8a;
`;

export const ActionsWrapper = styled.div`
  margin-left: 10px;
  padding: 10px 0;
  display: flex;
`;

export const Button = styled.button`
  width: 100%;
  margin-right: 10px;
  margin-top: 4px;
  border: 0;
  border-radius: 15px;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.08);
  padding: 10px 0;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.02, 0.01, 0.47, 1);

  &:hover {
    box-shadow: 0 15px 15px rgba(0, 0, 0, 0.16);
  }
`;

You will now need to import these at the top of App.js file and then change the JSX to use these styled components.

...
import {
  CardWrapper,
  ImageWrapper,
  TextWrapper,
  TitleWrapper,
  DescriptionWrapper,
  ActionsWrapper,
  Button,
} from "./styles";

...

{hotels.map((hotel) => {
    return (
        <CardWrapper key={hotel.id}>
            <ImageWrapper src={hotel.src} alt={hotel.alt} />
            <TextWrapper>
                <TitleWrapper>{hotel.title}</TitleWrapper>
                <DescriptionWrapper>{hotel.description}</DescriptionWrapper>
            </TextWrapper>
            <ActionsWrapper>
                <Button>Details</Button>
                <Button>Book</Button>
            </ActionsWrapper>
        </CardWrapper>
    );
})}

In the browser, you should now see the following:

*Composition *
Great, the app styling is nearing completion! You probably want to distinguish between the buttons prompting the user to learn more or book a hotel. You can use composition to create variants.

At the bottom of styles.js file, create a PrimaryButton component and a SecondaryButton component that will style the Button component. To do this we just wrap the Button component in the styled() constructor.

You no longer need to export the Button component so you can remove the export keyword.

...
const Button = styled.button`
  ...
`;

export const PrimaryButton = styled(Button)`
  background-color: #03045e;
  color: #caf0f8;
`;

export const SecondaryButton = styled(Button)`
  background-color: #caf0f8;
  color: #03045e;
`;

Finally, you need to import these at the top of App.js file and then change the JSX to use these components. Notice that we remove Button from the import statement and added in PrimaryButton and SecondaryButton.

import {
  CardWrapper,
  ImageWrapper,
  TextWrapper,
  TitleWrapper,
  DescriptionWrapper,
  ActionsWrapper,
  PrimaryButton,
  SecondaryButton,
} from "./styles";



                <ActionsWrapper>
                  <PrimaryButton>Details</PrimaryButton>
                  <SecondaryButton>Book</SecondaryButton>
                </ActionsWrapper>

This is the result on the browser:

*Theming *
The design is nearing completion. Now, suppose the design team decides that the primary color #03045e used in several locations throughout your app is too dark and they want to change it. This leads you to have to hunt through your app and change each occurrence, which might grow daunting as your app size grows. Theming to the rescue!

import styled from "@emotion/styled";

export const theme = {
  colors: {
    primary: "#03045e",
    secondary: "#caf0f8",
    tertiary: "#023e8a",
    quaternary: "#fff",
  },
  fonts: {
    primary: "helvetica",
  },
  fontSize: {
    primary: "20px",
    secondary: "14px",
  },
};

export const CardWrapper = styled.div`
  ...
  background: ${(props) => props.theme.colors.quaternary};
  ...
`;

The you are going to implement at the top level of your app will give you access to props.theme in your styled components. Go ahead and apply the rest of the theming to your styled components.

export const CardWrapper = styled.div`
  ...
  background: ${(props) => props.theme.colors.quaternary};
  ...
`;

...
export const TitleWrapper = styled.h2`
  ...
  font-size: ${(props) => props.theme.fontSize.primary};
`;

export const DescriptionWrapper = styled.h3`
  ...
  font-size: ${(props) => props.theme.fontSize.secondary};
  color: ${(props) => props.theme.colors.tertiary};
`;

...
export const PrimaryButton = styled(Button)`
  background-color: ${(props) => props.theme.colors.primary};
  color: ${(props) => props.theme.colors.secondary};
`;

export const SecondaryButton = styled(Button)`
  background-color: ${(props) => props.theme.colors.secondary};
  color: ${(props) => props.theme.colors.primary};
`;

At the top of our App.js file, import the ThemeProvider object from @emotion/react as well as import theme from styles.js file. Add the at the top level of the application which accesses the theme object. This will make the theme property available to all components in the React app.

You can also update the css prop in the tag to use the theme object properties and values.

import { css, ThemeProvider } from "@emotion/react";
import logo from "./logo.png";
import {
  theme, ...
} from "./styles"

...
function App() {
  {/* Wrap the entire content in a <ThemeProvider> */}
  return <ThemeProvider theme={theme}>
      <main
        css={(theme) => ({
          color: theme.colors.primary,
          background: theme.colors.secondary,
          height: "1200px",
          fontFamily: theme.fonts.primary,
        })}
      >
        ...
      </main>
    </ThemeProvider>
}

If you have done things correctly the app should look identical to your previous work:


You can test this by making changes in the theme object and seeing the changes reflected in multiple locations in your app.

*Keyframes / Animation *

The last step is to add some animation to the app. You can define animations using the keyframes helper from @emotion/react. keyframes takes in a CSS keyframe definition and returns an object you can use in styles. You can use strings or objects just like css.

At the top of styles.js file, import keyframes from @emotion/react and then define a LogoSpin keyframe below the theme object.

...
import styled from "@emotion/styled";
import { keyframes } from "@emotion/react";

export const theme = {
  ...
};

export const LogoSpin = keyframes`
from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;

Finally, import the LogoSpin keyframe in App.js and update the JSX.

...
import {
  LogoSpin,
  ...
} from "./styles";

...
<img
    src={logo}
    alt=""
    css={css`
        ...
        animation: ${LogoSpin} 10s linear infinite;
    `}
/>

Here is the link to the solution code . Check it out https://github.com/kibetamos/Emotion-library
That’s it! The logo should be rotating 360 degrees every 10 seconds.

Putting It All Together

In this tutorial, you learned how to use the Emotion library as an example of CSS-in-JS. You were able to create styled components, add styles to them, and use them in a React app. You learned how to create a theme object and apply styles to styled components. You also learned how to use the keyframes helper to add animation to your app.

Consider using Emotion in your next project to utilize CSS-in-JS. Happy coding!

좋은 웹페이지 즐겨찾기