Overriding styles in semantic ui react

FrobberOfBits picture FrobberOfBits · Mar 5, 2019 · Viewed 11k times · Source

I'm using Semantic UI React and trying to figure the best way to override default styles, so that I can change the appearance of cards and the overall theme.

Option 1 seems to be to define my CSS and put !important after every rule, which is not great.

Option 2 is the theming support, which sounds like what I want, except I cannot determine how to get started with that. My app is using CRA, and I'm a bit lost in documentation between changing my webpack configuration file (I don't have one), out of date blog posts from 2017 advising me to install a bunch of modules whose purpose is unclear, and the theming site itself which is advising me to define flexible variable files (an approach I like).

I can't determine why my theme files aren't getting picked up though, and it appears some sort of build fix is necessary that isn't covered by the theming guide.

What's the best way to get theming working while using a CRA build process? (./node_modules/.bin/react-scripts build)

Answer

Joshua Robinson picture Joshua Robinson · Mar 5, 2019

Specificity is king. Only time would need to use !important would be when inline style is present and the library does not expose a way to toggle the property off in some way (poor architecture choice).

The following list of selector types increases by specificity:

Type selectors (e.g., h1) and pseudo-elements (e.g., ::before).

Class selectors (e.g., .example), attributes selectors (e.g., [type="radio"]) and pseudo-classes (e.g., :hover).

ID selectors (e.g., #example).

https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Take a look at the first UI Button for Semantic UI here, is comprised of the following HTML:

<button class="ui button">Click Here</button>

CSS is attached via semantic.min.css:

.ui.button {
    cursor: pointer;
    display: inline-block;
    min-height: 1em;
    outline: 0;
    border: none;
    vertical-align: baseline;
    background: #e0e1e2 none;
    color: rgba(0,0,0,.6);
    font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
    margin: 0 .25em 0 0;
    padding: .78571429em 1.5em .78571429em;
    text-transform: none;
    text-shadow: none;
    font-weight: 700;
    line-height: 1em;
    font-style: normal;
    text-align: center;
    text-decoration: none;
    border-radius: .28571429rem;
    -webkit-box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    will-change: '';
    -webkit-tap-highlight-color: transparent;
}

To override say, the font color, all we have to do is write a selector that is more specific than this selector. We can achieve this by combining their two class selectors (equally specific) with a type selector (additional specificity).

This would look like:

button.ui.button {
  color: red;
}

Now since button.ui.button is more specific in describing the location of the element in the page (DOM), than say just .ui.button, this signals to the browser that this style should override the previous declaration. This is a common way to customize a theme.

Great docs here: https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS

.ui.button {
    cursor: pointer;
    display: inline-block;
    min-height: 1em;
    outline: 0;
    border: none;
    vertical-align: baseline;
    background: #e0e1e2 none;
    color: rgba(0,0,0,.6);
    font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
    margin: 0 .25em 0 0;
    padding: .78571429em 1.5em .78571429em;
    text-transform: none;
    text-shadow: none;
    font-weight: 700;
    line-height: 1em;
    font-style: normal;
    text-align: center;
    text-decoration: none;
    border-radius: .28571429rem;
    -webkit-box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    will-change: '';
    -webkit-tap-highlight-color: transparent;
}

button.ui.button {
  color: red;
}
<button class="ui button">Click Here</button>