--- tags: css --- # @emotions Styling and Theming with React and Emotion CSS Prop Pros 1. Similar to ==native inline style prop== but more powerful 2. Styles live within the ==component level== 3. Manipulate styles ==with props/state dynamically== [CodeSandBox範例](https://codesandbox.io/s/1zqqqv1zn7) ## [@emotion VS style component](https://www.youtube.com/watch?v=AqFqduEEw7A) ### [Style Component](https://medium.com/@shihKai/%E4%BB%8B%E7%B4%B9%E6%92%B0%E5%AF%ABreact-css%E7%9A%84%E7%A5%9E%E5%A5%97%E4%BB%B6styled-components-77455c849198) 1. React允許您直接使用樣式屬性設置組件樣式。 2. 它接受一個樣式屬性的對象,對於大多數用例來說,它已經綽綽有餘了。 3. 但作為單個屬性,無法指定更細微的默認值 ### @emotion 1. 支持!important 屬性(非css style原生) 2. 有彈性且高性能的CSS-in-JS庫。 3. 它接受字符串和對象 4. 支持默認值(defaulting)和擴展變量(extended variable) 5. 附加的Babel插件 6. 支持 inline childe selectors ## BASIC : Passing Props [npm](https://emotion.sh/docs/introduction) ``` npm i emotion npm i @emotion/core npm i @emotion/styled @emotion/core ``` ### 初階範例 ```javascript= import styled, { css } from "react-emotion"; // 使用方式 // const 物件 = styled('htmltag or @emotion tag') or styled.htmltag` // 該物件的css屬性 // props { // css屬性值 // } // ` // 兩種傳遞props的方式 const Heading = styled('h1')` background-color: ${props => props.bg}; /* 下層引用使用bg="#???" */ color: ${props => props.fg}; `; // 1. ` css: ${ props => props.xxx };` // 引用時要用 xxx={num} 或 xxx=“num”都可以; const Cite = styled.cite( { fontWeight: 100 // 預設值 }, props => ({ fontWeight: props.weight // 下層引用使用 weight={num} })); // 2. `css`直接寫成( props => ({ css: props.xxx })) // 參數依然是css屬性,引用時要用 xxx="?px" ``` ### 進階範例 1. 製作@emotions元素 Just like styled component ```javascript= import styled from '@emtion/styled'; const Icon = styled('svg')` path { transition: 0.2s; fill: ${p => (p.color ? p.color : (p.active ? #red : #grey))}; width: ${p => p.width}px; } ` export default Icon ``` 2. 引入@emotions ```javascript= import React from 'react'; import styled from '@emtion/styled'; import Icon from '/IconBase'; // 先const一個name使用@emotion元素 // 在該已有該元素的前提下,再新增一些css屬性 const SVG = styled(Icon)` transform: scale(${p => (p.scale ? p.scale : 1)}); 有給scale就是該值,沒給就是1 path { width: 50px; } ` // 先const一個name,並有那四個元素可由子層指定 // 使用剛剛定義的SVG,並給定其內path屬性,實現可重複利用的TextBubble component const TextBubble = ({active, color, scale, className}) <SVG className={className} width="26" height="26" active={active} color={color} scale={scale} > <path d="M13 26C5.82 26 0 20.18 0 13S5.82 0 13 0s13 5.82 13 13-5.82 13-13 13zM8 8a1 1 0 1 0 0 2h10a1 1 0 0 0 0-2H8zm0 4a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2 H8zm0 4a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H8z" fill="#2B2B2B" fillRule="evenodd" /> </SVG> export default TextBubble; ``` ## RWD ### 設定各螢幕大小的底層component:MediaQuery ```javascript= import { css } from '@emotion/core'; const breakpoints = { mobile: 479, portraitTablet: 767, tablet: 1023, desktop: 1199, }; const mq = Object.keys(breakpoints).reduce((accumulator, label) => { const prefix = typeof breakpoints[label] === 'string' ? '' : 'max-width: '; const suffix = typeof breakpoints[label] === 'string' ? '' : 'px'; accumulator[label] = cls => css` @media (${prefix + breakpoints[label] + suffix}) { ${css` ${cls}; `}; } `; return accumulator; }, {}); export default mq; ``` ### 引用層 ```javascript= // @flow import React from 'react'; import styled from '@emotion/styled'; import mq from '../../../MediaQuery'; const ContentWrapper = styled.div` width: 100%; display: flex; justify-content: flex-start; align-items: flex-start; margin: 100px 0 120px 0; ${mq.desktop` padding: 0 32px; `} ${mq.portraitTablet` display: block; max-width: 640px; flex-direction: column; margin: 20px; `} `; const TabletWrapper = styled.div` flex-grow: 1; flex-shrink: 1; flex-basis: 0; margin: 0 30px 0 0; ${mq.portraitTablet` margin: 0; display: flex; flex-direction: column; `} `; const MediaWrapper = styled.div` display: none; ${mq.tablet` display: block; width: 100%; `} ` // 預設是display: none; // 當畫面滿足 mq.tablet的條件時,就會執行內區的css屬性 // mq裡有設好tablet的大小,如上 function xxx() { return ( <MediaWrapper> 要顯示的東西 </MediaWrapper> ); } ``` --- 想知道更多歡迎參閱 [官方文件](https://emotion.sh/docs/introduction)