styled-components / styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
https://styled-components.com
MIT License
40.46k stars 2.5k forks source link

Combining referentially equal css tags #2711

Closed chrbala closed 4 years ago

chrbala commented 5 years ago

This is mostly a question, but could potentially be a feature request if it makes sense. Basically, I'm wondering why referential equal css aren't deduped in the stylesheets, as illustrated below:

import React from 'react';
import { renderToString } from 'react-dom/server';
import styled, { ServerStyleSheet, css } from 'styled-components';

const greenColor = css`
    color: green;
`;
const Green = styled.div`
    ${greenColor};
`;
const AlsoGreen = styled.div`
    ${greenColor};
`;
const App = () => (
    <div>
        <Green />
        <AlsoGreen />
    </div>
);

const sheet = new ServerStyleSheet();
renderToString(sheet.collectStyles(<App />));
const styleTags = sheet.getStyleTags();

styleTags renders to the following:

<style type="text/css" data-styled-components="cZgqpQ dwaWry" data-styled-components-is-local="true">/* sc-component-id: sc-bdVaJa */

.cZgqpQ{color:green;}
/* sc-component-id: sc-bwzfXH */

.dwaWry{color:green;}
</style>

If the components are combined differently, only one CSS class is generated:

const greenColor = css`
  color: green;
`;
const Green = styled.div`
  ${greenColor};
`;
const AlsoGreen = styled(Green)``;

Results in

<style type="text/css" data-styled-components="cZgqpQ bFHdpU" data-styled-components-is-local="true">/* sc-component-id: sc-bdVaJa */

.cZgqpQ{color:green;}
/* sc-component-id: sc-bwzfXH */

</style>

Is there something that prevents combining those css classes? I've looked around for other tickets on css class optimization and just found https://github.com/styled-components/styled-components/issues/351.

Tested with styled-components 3.1.6.

quantizor commented 4 years ago

@kitten might be able to answer this better, but to my understanding it's largely in the pursuit of scope isolation and preventing unintended collisions between components.

You're not going to see a css-in-js library that effectively achieves this goal unless they're desugaring to more of an atomic css-style output (which has its own problems.)

kitten commented 4 years ago

We care a lot of specificity, which explains why classes and rules aren’t reused. This is somewhat different between different CSS-in-JS libraries.

Some optimise these cases and treat identical rules as identical regardless of what they’re targeting. There are also atomic libraries that aim to reuse as much as possible.

styled-components falls into the third category, which may be somewhat of a strict and predictable approach.

Sets of rules for StyledComponents are injected in the order they’re defined in and in the order that the components are defined in. When a component is defined you can imagine a slot or index to be allocated in the background (which actually happens now in v5). The rules of a component that is defined after another can then never come before it. So ordering is kept very strictly, which prevents styling issues, where another one of your rules that is defined after another suddenly doesn’t take precedence anymore because it has been inserted before another.

Hope that makes sense ✌️