【问题标题】:CSS pseudo elements in ReactReact 中的 CSS 伪元素
【发布时间】:2015-03-31 22:08:40
【问题描述】:

我正在构建React 组件。我已按照 React 背后的一位人员在 this brilliant presentation 中的建议在组件中添加了 CSS 内联。我一直在努力寻找一种方法来内联添加 CSS 伪类,就像演示文稿中标题为“::after”的幻灯片一样。不幸的是,我不仅需要添加content:""; 属性,还需要添加position:absolute; -webkit-filter: blur(10px) saturate(2);。幻灯片展示了如何通过{/* … */} 添加内容,但是您将如何添加其他属性?

【问题讨论】:

    标签: javascript css reactjs pseudo-element


    【解决方案1】:

    在React 团队收到@Vjeux 的回复:

    普通 HTML/CSS:

    <div class="something"><span>Something</span></div>
    <style>
        .something::after {
        content: '';
        position: absolute;
        -webkit-filter: blur(10px) saturate(2);
    }
    </style>
    

    用内联样式响应:

    render: function() {
        return (
            <div>
              <span>Something</span>
              <div style={{position: 'absolute', WebkitFilter: 'blur(10px) saturate(2)'}} />
            </div>
        );
    },
    

    诀窍在于,不要在 CSS 中使用 ::after 来创建新元素,而应该通过 React 创建新元素。如果您不想在任何地方都添加此元素,请制作一个组件来为您完成。

    对于像-webkit-filter 这样的特殊属性,对其进行编码的方法是删除破折号 - 并将下一个字母大写。所以它变成了WebkitFilter。请注意,执行 {'-webkit-filter': ...} 也应该有效。

    【讨论】:

    • 强制性抱歉回答我自己的问题。感谢@Vjeux 的回答。效果非常好!
    • 但是,当 React JS 被呈现给搜索代理时,它们会索引伪内容,这并不好。例如,如果您将标题复制到::after-元素中,以创建自定义阴影,仅出于样式目的,当 Google 看到它时,我不会在 DOM 中,但通过这种方法,Google 会看到它。 .. 意味着您将有两个头条新闻。
    • 太糟糕了,当你在 react 中搜索伪元素时,它会在顶部弹出。 @vjeux 可能会非常恼火地说 css 很糟糕,但实际上并没有为其 react-followers 提供干净/完整的替代方案。这个解决方案不应该被接受,它是一个倒退——顺便说一句,它确实工作得很好啊啊啊
    • 我认为这不是一个合适的解决方案。我使用之前和之后的伪元素来避免创建不必要的 DOM。
    • 这没有回答问题,创建一个新元素而不是使用伪元素是不够的解决方案
    【解决方案2】:

    内联样式不能用于定位伪类或伪元素。您需要使用样式表。

    如果要动态生成 CSS,那么最简单的方法是创建一个 DOM 元素&lt;style&gt;。

    <style dangerouslySetInnerHTML={{
      __html: [
         '.my-special-div:after {',
         '  content: "Hello";',
         '  position: absolute',
         '}'
        ].join('\n')
      }}>
    </style>
    <div className='my-special-div'></div>
    

    【讨论】:

      【解决方案3】:

      内联样式不支持伪规则或 at 规则(例如,@media)。建议的范围从在 JavaScript 中针对 CSS 状态(例如 :hover 通过 onMouseEnter 和 onMouseLeave 重新实现 CSS 功能)到使用更多元素来重现伪元素(例如 :after 和 :before)到仅使用外部样式表。

      个人不喜欢所有这些解决方案。通过 JavaScript 重新实现 CSS 功能并不能很好地扩展——添加多余的标记也不能。

      想象一个大型团队,其中每个开发人员都在重新创建 CSS 功能,例如 :hover。随着团队规模的扩大,每个开发人员会做不同的事情,如果可以做到,就会做到。事实上,在 JavaScript 中,有大约 n 种方法可以重新实现 CSS 功能,随着时间的推移,您可以押注其中的每一种实现方式,最终结果都是意大利面条式代码。

      那该怎么办?使用 CSS。当然,您询问内联样式会假设您可能在 CSS-in-JS 阵营(我也是!)。已经发现 HTML 和 CSS 与 JS 和 HTML 一样有价值,但很多人还没有意识到这一点(JS-HTML 并置一开始也有很多阻力)。

      在这个空间中提出了一个名为 Style It 的解决方案,它可以让您在 React 组件中编写纯文本 CSS。无需浪费循环在 JS 中重新发明 CSS。适合工作的正确工具,这里是使用 :after 的示例:

      npm install style-it --save

      函数语法 (JSFIDDLE)

      import React from 'react';
      import Style from 'style-it';
      
      class Intro extends React.Component {
        render() {
          return Style.it(`
            #heart {
              position: relative;
              width: 100px;
              height: 90px;
            }
            #heart:before,
            #heart:after {
              position: absolute;
              content: "";
              left: 50px;
              top: 0;
              width: 50px;
              height: 80px;
              background: red;
              -moz-border-radius: 50px 50px 0 0;
              border-radius: 50px 50px 0 0;
              -webkit-transform: rotate(-45deg);
              -moz-transform: rotate(-45deg);
              -ms-transform: rotate(-45deg);
              -o-transform: rotate(-45deg);
              transform: rotate(-45deg);
              -webkit-transform-origin: 0 100%;
              -moz-transform-origin: 0 100%;
              -ms-transform-origin: 0 100%;
              -o-transform-origin: 0 100%;
              transform-origin: 0 100%;
            }
            #heart:after {
              left: 0;
              -webkit-transform: rotate(45deg);
              -moz-transform: rotate(45deg);
              -ms-transform: rotate(45deg);
              -o-transform: rotate(45deg);
              transform: rotate(45deg);
              -webkit-transform-origin: 100% 100%;
              -moz-transform-origin: 100% 100%;
              -ms-transform-origin: 100% 100%;
              -o-transform-origin: 100% 100%;
              transform-origin :100% 100%;
            }
          `,
            <div id="heart" />
          );
        }
      }
      
      export default Intro;
      

      JSX 语法 (JSFIDDLE)

      import React from 'react';
      import Style from 'style-it';
      
      class Intro extends React.Component {
        render() {
          return (
            <Style>
            {`
              #heart {
                position: relative;
                width: 100px;
                height: 90px;
              }
              #heart:before,
              #heart:after {
                position: absolute;
                content: "";
                left: 50px;
                top: 0;
                width: 50px;
                height: 80px;
                background: red;
                -moz-border-radius: 50px 50px 0 0;
                border-radius: 50px 50px 0 0;
                -webkit-transform: rotate(-45deg);
                -moz-transform: rotate(-45deg);
                -ms-transform: rotate(-45deg);
                -o-transform: rotate(-45deg);
                transform: rotate(-45deg);
                -webkit-transform-origin: 0 100%;
                -moz-transform-origin: 0 100%;
                -ms-transform-origin: 0 100%;
                -o-transform-origin: 0 100%;
                transform-origin: 0 100%;
              }
              #heart:after {
                left: 0;
                -webkit-transform: rotate(45deg);
                -moz-transform: rotate(45deg);
                -ms-transform: rotate(45deg);
                -o-transform: rotate(45deg);
                transform: rotate(45deg);
                -webkit-transform-origin: 100% 100%;
                -moz-transform-origin: 100% 100%;
                -ms-transform-origin: 100% 100%;
                -o-transform-origin: 100% 100%;
                transform-origin :100% 100%;
              }
           `}
      
            <div id="heart" />
          </Style>
        }
      }
      
      export default Intro;
      

      从CSS-Tricks提取的心脏示例

      【讨论】:

        【解决方案4】:

        根据您是否只需要内联样式设置几个属性,您可以执行类似此解决方案的操作(并且无需安装特殊包或创建额外元素):

        https://stackoverflow.com/a/42000085

        <span class="something" datacustomattribute="?">
          Hello
        </span>
        
        .something::before {
          content: attr(datascustomattribute);
          position: absolute;
        }
        

        注意datacustomattribute 必须以data 开头并且全部小写以满足React。

        【讨论】:

        • 另外请注意,虽然它必须是小写,但它也可以包含破折号,例如data-custom-attribute 也可以使用
        • 截至 2021 年 7 月,如 MDN docs 中所述: attr() 函数可与任何 CSS 属性一起使用,但对内容以外的属性的支持是实验性的,并且支持 type-or -unit 参数是稀疏的。
        【解决方案5】:

        您可以使用样式化组件。

        用npm i styled-components安装它

        import React from 'react';
        import styled from 'styled-components';
        
        const YourEffect = styled.div`
          height: 50px;
          position: relative;
          &:after {
            // whatever you want with normal CSS syntax. Here, a custom orange line as example
            content: '';
            width: 60px;
            height: 4px;
            background: orange
            position: absolute;
            bottom: 0;
            left: 0;
          },
        
        const YourComponent = props => {
          return (
            <YourEffect>...</YourEffect>
          )
        }
        
        export default YourComponent
        

        【讨论】:

          【解决方案6】:

          我不知道这是否会被认为是 hacky,但它确实有效(使用 CSS 变量):

          const passedInlineStyle = { '--color':'blue'}
          

          然后在一个导入的 CSS 文件中:

          background:var(--color);
          

          【讨论】:

            【解决方案7】:

            不是问题的直接答案,但这可能会帮助那些在使用 Typescript 创建style 信息时遇到困难的人。

            我收到一条错误消息,告诉我以下内容不正确:

            let iconStyle = {
                position: 'relative',
                maxHeight: '90px',
                top: '25%',
            }
            

            错误告诉我“属性‘位置’的类型不兼容”。我不知道为什么。

            我通过添加严格的 Typescript 声明来解决此问题,如下所示:

            let iconStyle: CSSProperties = {
                position: 'relative',
                maxHeight: '90px',
                top: '25%',
            }
            

            这行得通。

            【讨论】:

            • 问题实际上与 TypeScript 无关。
            • @phillyslick 是的。用 Typescript 编写时,给定的答案会引发错误。我为该错误提供了解决方案。
            • 您的答案是关于如何键入 CSS 属性,特别是位置属性类型以及为什么不能使用字符串。对此有一些解决方案(您建议一个好的解决方案),但同样,这个问题与 TypeScript 无关。它是关于 JavaScript、React 和 CSS 的。来到这里的人都不应该认为 TypeScript 与这个问题或其给定的解决方案有任何关系。
            • @phillyslick 你肯定知道 Javascript 和 Typescript 有多少重叠?在使用 React 时,我(当然还有其他人)已经无数次地寻找问题的解决方案,并找到了一个用 Javascript 编写的解决方案,它在 Typescript 中同样适用。然而,有时,例如上述情况,情况并非如此。对我来说,添加一个带有小调整的注释以使上述解决方案适用于那些在 Typescript 中遇到 React CSS 问题的人,这几乎不是武断的飞跃。老实说,我根本看不出你有什么大问题。
            • 我的“大问题”是您的回答对不使用 TypeScript 的人没有帮助。目前,您的答案高于已接受的答案。然而,它并没有回答这个问题——你自己这么说。它回答了一个可能的问题一些用户可能有,这与问题无关。当有人在他们的管道中使用 SASS 时会发生什么,我们也应该回答这个问题吗? React Native 呢?有人可能会争辩说,这与 TypeScript 一样与 React 无关。明白我的意思了吗?
            猜你喜欢
            • 2020-09-20
            • 2017-10-05
            • 1970-01-01
            • 2016-05-02
            • 2020-10-16
            • 1970-01-01
            • 2023-03-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多