JS에 CSS를 두고 좋은 이전 CSS 프로세서로 돌아가는 이유

41092 단어 reactcsswebdevsass
2021년 5월 30일 편집.CSS 변수에 대한 정보가 추가되었습니다.
나는 일찍이 JS의 CSS(JSS)를 매우 좋아했지만, 지금은 다시 예처리된 CSS로 돌아왔다.회귀기술 공포증?아니면 합리적인 선택?설명 좀 할게요.

1. JSS가 해결한 문제
우선 JSS는 개념적 증명만이 아니라 두 가지 난제를 해결했다.'해결' 이라는 뜻으로 그것들을 완화시키는 수단만 제공하는 것이 아니다.

1.1. 모듈 범위 CSS
CSS는 본질적으로 전 세계적이다.CSS 파일을 모듈로 가져오는 것은 모듈 역할 영역처럼 보일 수 있지만 실제로는 그렇지 않습니다.

A.css
.a {
  color: red;
}

A.jsx
import './A.css'
function A() {
  return <span class='b'>Hi</span>
}
문제 보셨어요?
대답하다.A.jsxb에서 언급하지 않은 A.css류를 사용했다.
JSS 및 TypeScript를 사용하면 이러한 오류가 발생할 수 없습니다.

A.tsx
const useStyles = createUseStyles({
  a: {
    color: 'red';
  }
})

function A() {
  const styles = useStyles()
  return <span class={styles.b}>Hi</span>
}
A.tsx는 컴파일할 수 없습니다.

1.2. CSS와 JS 간에 변수 공유
가능한 비 JSS 솔루션은 css-modules에서 지원되는 css-loader입니다. 이것은 약간의 설정이 필요합니다.새 브라우저의 경우 CSS custom propertiesgetComputedStyle가 함께 작동합니다.
JSS가 있으면 일은 가능한 한 간단해진다. 너는 일반적인 JS 변수 하나만 있으면 된다. 네가 쓰고 싶은 대로 써라!
const itemHeight = 72
const useStyles = createUseStyles({
  item: {
    height: itemHeight,
  },
})

function Showcase({items, topItem}) {
  const styles = useStyles()

  return <div style={{translateY: -itemHeight * topItem}}>
    {
      items.map(item =>
        <div class={styles.item}>{item}</div>
      )
    }
  </div>
}

2.가격

2.1. 성과 벌금
styled-componentsreact-jss의 가방 비용은 각각 33kB와 61kB로 축소되었다.또 하나는runtime overhead,이것은is not argued,심지어libs의 저자이다.

2.2. 개발자의 경험이 실제로는 더 나쁘다
편집자는 CSS를 알고 있습니다.그들은 문법 강조 표시, 코드 완성, 기타 도움말 서비스를 제공한다.JS가 생기면 많은 것을 놓치게 될 것이다. 왜냐하면 IDE는 JS 대상만 볼 수 있기 때문이다.
const styles = createUseStyles({
  btn: {
    border: '1px dark gray',
    boxSizing: 'border',
    padding: '4px 12px',
    whiteSpace: 'nowrap',
  },
});
심심해 보이고 실수하기 쉽다.겸사겸사 한마디 하자면, 너는 발견했니?
대답하다.
색상은 darkgray이지 dark gray여야 합니다.IDE가 도움이 되지 않음;하지만 CSS가 있으면
스타일링 구성 요소 문법이 더 엉망입니다.
const Btn = styled.button`
    border: 1px dark gray;
    boxSizing: border;
    padding: 0 12px 6px;
    whiteSpace: nowrap;
`

2.3. Libs에는 우울한 버그가 포함될 수 있습니다.
예제this one 참조.이 간단한 질의가 작동하지 않는 경우가 있습니다.
const styles = createUseStyles({
  item: ({param}) => ({
    '@media (min-width: 320px)': {
      // ...
    },
  }),
})
문제는 1년 전이다.이것은 구석이 아닌 하찮은 용법이지만, 여전히 개방되어 있다. making devs suffer정말 아깝다!

3. 그렇다면 JSS는 가치가 있는가?
나는 기술을 선택하는 것이 균형의 문제라는 것을 안다.어떤 사람은 이익이 폐단보다 크다는 것을 발견할 수 있다.개인적으로 JSS의 성능과 개발 경험이 가치가 있는지 의심스럽습니다.
근데 JS 없이 어떻게 살아요?유행하는 옵션을 보여 주세요.

3.1. CSS modules
CSS 모듈도 클래스 이름을 생성하지만 JS와 달리 컴파일할 때 클래스 이름을 생성하고 실행할 때 비용을 분배하지 않습니다.만약 당신configured everything correctly이 이렇다면:

유리 진열장.css
.showcase {
  display: flex;
}
.item {
  width: 33%;
}
.highlighted {
  background-color: lightgray;
}

유리 진열장.css.d, td(생성됨)
export const showcase: string
export const item: string
export const highlighted: string

유리 진열장.tsx
import styles from './Showcase.css'

type Props = {items: string[], highlighted: number}

function Showcase({items, highlighted}: Props) {
  return <div className={styles.showcase}>{
    items.map((item, i) => {
      const c = `${styles.item} ${i===highlighted ? styles.highlighted : ''}`
      return <div className={c}>{item}</div>
    })
  }</div>
}
괜찮아 보여요!JSS의 장점이 있지만 실행 시 벌칙이 삭제되었습니다.그러나 보시다시피 type definitions generated가 있기 때문에 개발 과정을 순조롭게 하기 위해서는 적절한 설정을 하고 코드를 작성할 때 개발 서버를 시종일관 실행해야 합니다.물론 이것은 나의 경험이다.

3.2. BEM
BEM은 가장 유명한 CSS 클래스 이름 규약일 수 있습니다.전체 사양은 상세해 보이지만 본질은 간단합니다.
  • BEM은 블록, 요소, 수정기
  • 를 나타냅니다.
  • 블록은 어셈블리의 최상위 DOM 요소입니다.
  • 블록 이름은 프로젝트에서 고유해야 함
  • 원소는 블록 내부의 물건이다
  • 요소 이름은 block__element
  • Modifier는 블록이나 요소를 조정하는 클래스입니다.
  • 블록 수정기 이름은 block_modifier
  • 요소 수정기 이름은 block__element_modifier
  • CSS 사전 프로세서 및 JS 클래스prefixers를 사용하면 이름을 계속 반복할 필요가 없습니다.

    유리 진열장.scss
    .showcase {
      display: flex;
      &__item {
        width: 33%;
        &_highlighted {
          background-color: lightgray;
        }
      }
    }
    

    유리 진열장.jsx
    import './Showcase.scss';
    import {withNaming} from '@bem-react/classname';
    
    const cn = withNaming({e: '__', m: '_', v: '_' })
    
    const showcaseCn = cn('showcase');
    const itemCn = cn('showcase', 'item')
    
    function Showcase({items, highlighted}) {
      return <div className={showcaseCn()}>{
        items.map((item, i) => {
          const c = itemCn({highlighted: i===p.highlighted})
          return <div className={c}>{item}</div>
        })
      }</div>
    }
    
    
    

    BEM 과정을 간소화할 수 있습니까?
    나는 BEM을 매우 좋아하지만, 접두사나 긴 명칭을 사용하는 것은 나에게 매우 지루한 것 같다.만약 우리가 CSS 조합부호로 그것들을 바꾸면?한 번 시도해 봅시다.

    유리 진열장.scss
    .b-showcase {
      display: flex;
      >.item {
        width: 33%;
        &.highlighted {
          background-color: lightgray;
        }
      }
    }
    

    유리 진열장.jsx
    import './Showcase.scss';
    
    function Showcase({items, highlighted}) {
      return <div className='b-showcase'>{
        items.map((item, i) => {
          const c = `item ${i===p.highlighted ? 'highlighted' : ''}`
          return <div className={c}>{item}</div>
        })
      }</div>
    }
    
    이게 더 자연스러워 보여요.노트:
  • b- 블록 이름이 아닌 경우
  • 와 충돌하지 않도록 접두어가 필요합니다.

  • Descendant combinator 은(는) 실수로 네스트된 블록
  • 에서 엔티티를 선택할 수 있으므로 사용되지 않습니다.
  • 요소 깊이가 알 수 없는 경우 BEM
  • 으로 폴백 가능
  • 매우 큰 응용 프로그램에서 하위 선택기의 작업 속도는 간단한 BEM류보다 느릴 수 있다.다른 한편, 접두사를 사용하지 않고 실행할 때

  • 어떻게 블록 클래스가 대형 응용 프로그램에서 유일하다는 것을 확보합니까?
    이것은 아마도 BEM의 가장 어려운 부분일 것이다.그러나 scss-parser의 도움말 아래 SCSS 파일을 분석하고 검증하는 프로그램(또는 패키지 플러그인)을 작성할 수 있습니다.

    검증하다.ts(약식)
    import {parse} from 'scss-parser'
    
    const clsToFile = new Map<string, string>()
    for await (const file of walkDir(__dirname)) {
      const cn = getTopLevelClass(String(await fs.promises.readFile(file)))
      if (!cn) {
        throw new Error(`No top level class: ${file}`)
      }
      if (clsToFile.has(cn)) {
        throw new Error(`Duplicate class '${cn}' in ${clsToFile.get(cn)} and ${file}` )
      }
      clsToFile.set(cn, file)
    }
    
    // Walks a dir recursively yielding SCSS files
    async function* walkDir(dir: string): AsyncGenerator<string> {
      // ...
    }
    
    // Returns top-level class if there is one
    function getTopLevelClass(scss: string) {
      const ast = parse(scss)
      // ...
    }
    
    완전 검증.ts
    import {parse, Node} from 'scss-parser'
    import fs from 'fs'
    import path from 'path'
    
    main()
    
    main() {
      const clsToFile = new Map<string, string>()
      for await (const file of walkDir(__dirname)) {
        const cn = getTopLevelClass(String(await fs.promises.readFile(file)))
        if (!cn) {
          throw new Error(`No top level class: ${file}`)
        }
        if (clsToFile.has(cn)) {
          throw new Error(`Duplicate class '${cn}' in ${clsToFile.get(cn)} and ${file}` )
        }
        clsToFile.set(cn, file)
      }
    }
    
    async function* walkDir(dir: string): AsyncGenerator<string> {
      const entries = await fs.promises.readdir(dir, {withFileTypes: true})
      for (const e of entries) {
        const file = path.resolve(dir, e.name)
        if (e.isFile() && /\.scss$/.exec(e.name)) {
          yield file
        } else if (e.isDirectory()) {
          yield* walkDir(file)
        }
      }
    }
    
    function getTopLevelClass(scss: string) {
      const ast = parse(scss)
      if (Array.isArray(ast.value)) {
        const topLevelClasses = ast.value
          .filter(node => node.type === 'rule')
          .flatMap(ruleNode => ruleNode.value as Node[])
          .filter(node => node.type === 'selector')
          .flatMap(selectorNode => selectorNode.value as Node[])
          .filter(node => node.type === 'class')
          .flatMap(classNode => classNode.value as Node[])
          .filter(node => node.type === 'identifier')
          .map(identifierNode => identifierNode.value as string);
        if (topLevelClasses.length === 1) {
          return topLevelClasses[0];
        }
      }
    }
    

    변수 공유 어떡하지?
    이것은 결코 그렇게 간단하지는 않지만 몇 가지 선택이 있다.
  • 사용getComputedStyle하면 유효한 응용 프로그램의 CSS 값을 얻을 수 있습니다custom property(새 브라우저만 해당)
  • 원소 크기와 편이량을 얻으려면 조회 가능getBoundingClientRect
  • 애니메이션 타이밍에 따라 내용을 지정하는 대신 onanimationendontransitionend
  • 를 사용할 수 있습니다.
    요구 사항에 맞지 않는 경우 다음과 같은 몇 가지 명명 규칙을 도입할 수 있습니다.

    유리 진열장.scss
    $shared-pad-size: 6px;
    
    .showcase {
      padding: $pad-size;
      // ..
    }
    

    유리 진열장.jsx
    const sharedPadSize = 6;
    
    export function Showcase() {
       // ...
    }
    

    3.3. Tailwind CSS
    솔직히 나는 그것을 좋아하지 않지만 2021년 CSS를 언급할 때 그것을 언급하지 않을 수는 없다.네.개발자들은 이 문제를 논쟁할 뿐만 아니라 이 문제를 논쟁할 수도 있다.이것은 매우 재미있지만, 나는 옆에 있을 것이다😉

    3.4. Web components
    이것은 완전히 다른 세계다.그것은 새로운 것이 아니지만, 모든 주류 브라우저가 그것을 완전히 지원하는 것은 아니다.어쩌면 이것이 미래의 주류일지도 모르는데, 누가 알겠는가🙂

    그래서 마지막으로...무엇을 선택하시겠습니까?
    이거 어려워요.은탄이 없고 타협과 절충이 있다.나는 연결되지 않은 경계원법이나 단지 경계원법을 더 좋아한다.너는?

    좋은 웹페이지 즐겨찾기