React 中的 CSS 伪元素

我正在构建 做出反应组件。我已经在组件中添加了 CSS 内联,正如反应背后的一个人在 这个精彩的演讲中所建议的那样。我整晚都在试图找到一种内联添加 CSS 伪类的方法,就像演示文稿中标题为“ : : after”的幻灯片那样。不幸的是,我不仅需要添加 content:"";属性,还需要添加 position:absolute; -webkit-filter: blur(10px) saturate(2);属性。幻灯片显示了如何通过 {/* … */}添加内容,但是如何添加其他属性呢?

174013 次浏览

Inline styles cannot be used to target pseudo-classes or pseudo-elements. You need to use a stylesheet.

If you want to generate CSS dynamically, then the easiest way is to create a DOM element <style>.

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

Got a reply from @Vjeux over at the React team:

Normal HTML/CSS:

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

React with inline style:

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

The trick is that instead of using ::after in CSS in order to create a new element, you should instead create a new element via React. If you don't want to have to add this element everywhere, then make a component that does it for you.

For special attributes like -webkit-filter, the way to encode them is by removing dashes - and capitalizing the next letter. So it turns into WebkitFilter. Note that doing {'-webkit-filter': ...} should also work.

Inline styling does not support pseudos or at-rules (e.g., @media). Recommendations range from reimplement CSS features in JavaScript for CSS states like :hover via onMouseEnter and onMouseLeave to using more elements to reproduce pseudo-elements like :after and :before to just use an external stylesheet.

Personally dislike all of those solutions. Reimplementing CSS features via JavaScript does not scale well -- neither does adding superfluous markup.

Imagine a large team wherein each developer is recreating CSS features like :hover. Each developer will do it differently, as teams grow in size, if it can be done, it will be done. Fact is with JavaScript there are about n ways to reimplement CSS features, and over time you can bet on every one of those ways being implemented with the end result being spaghetti code.

So what to do? Use CSS. Granted you asked about inline styling going to assume you're likely in the CSS-in-JS camp (me too!). Have found colocating HTML and CSS to be as valuable as colocating JS and HTML, lots of folks just don't realise it yet (JS-HTML colocation had lots of resistance too at first).

Made a solution in this space called Style It that simply lets your write plaintext CSS in your React components. No need to waste cycles reinventing CSS in JS. Right tool for the right job, here is an example using :after:

npm install style-it --save

Functional Syntax (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 Syntax (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;

Heart example pulled from CSS-Tricks

Not a direct answer to the question, but this may help those who are having trouble creating style information using Typescript.

I was getting an error telling me that the following was incorrect:

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

The error told me that "types of property 'position' are incompatible". I have no idea why.

I fixed this by adding a strict Typescript declaration, like so:

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

This works.

You can use styled components.

Install it with npm i styled-components

import React from 'react';
import styled from 'styled-components';


const ComponentWithPseudoClass = 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 (
<ComponentWithPseudoClass>...</ComponentWithPseudoClass>
)
}


export default YourComponent

Depending if you only need a couple attributes to be styled inline you can do something like this solution (and saves you from having to install a special package or create an extra element):

https://stackoverflow.com/a/42000085

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

Note that the datacustomattribute must start with data and be all lowercase to satisfy React.

I don't know if this would be considered hacky but it certainly works (using CSS variable):

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

Then in an imported CSS file:

background:var(--color);