mightymouse3062 mightymouse3062 - 25 days ago 9
Sass (Sass) Question

Overriding react-bootstrap CSS with custom SASS

I am working to create a custom application using react and bootstrap with webpack and SASS. I have been able to hook everything up correctly (for the most part), except I am trying to override some of the default bootstrap styles inside of my react components but it does not seem to be working.

Here is my file structure

webpack.config.js
app/
--index.html
--main.scss
--renderer.js
--components/
----navigation/
------index.js


webpack.config.js

const path = require('path')
const webpack = require('webpack')

const myConfig = {
entry: [
path.resolve('./app/renderer.js'),
'webpack-hot-middleware/client?reload=true&path=http://localhost:5555/__webpack_hmr',
'webpack/hot/only-dev-server',
],

devtool: 'inline-source-map',
target: 'web',

module: {
loaders: [
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: 'style-loader!css-loader!sass-loader?sourceMap',
},
],
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
plugins: [
'transform-class-properties',
'transform-decorators-legacy',
'transform-es2015-classes',
'react-hot-loader/babel'
],
},
},
},
{
test: /.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]__[hash:base64:5]',
}
},
{
loader: 'sass-loader'
}
]
},
],
},

plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
],

output: {
path: path.join(__dirname, './app/static'),
filename: 'bundled.js',
publicPath: 'http://localhost:5555/static/',
},
}

module.exports = [ myConfig ]


index.html

<html>
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
</head>
<body>
<div id='root'></div>
<script src="http://localhost:5555/static/bundled.js"></script>
</body>
</html>


renderer.js

import React from 'react'
import ReactDOM from 'react-dom'

import './main.scss'

import Navigation from './components/navigation'

ReactDOM.render(
<Navigation />,
document.getElementById('root')
)


navigation/index.js

import React from 'react'
import { Navbar } from 'react-bootstrap'

export default class Navigation extends React.Component {
clickHandler = () => {
console.log("Hello World")
}

render() {
return (
<Navbar id="navigationRoot" inverse staticTop>
<Navbar.Header>
<Navbar.Brand>
<a onClick={this.clickHandler}>SiteName</a>
</Navbar.Brand>
</Navbar.Header>
</Navbar>
)
}
}


main.scss

.navbar-brand {
color: #FF0000;
}


In the main.scss I have tried to override the color of the bootstrap navbar-brand style as an example from the SASS file, however it appears that the bootstrap.min.css file does not allow me to override the style. I know that the main.scss file is being included in the renderer build because I can add something like this to main.scss and the style is picked up in the webpage.

body {
background-color: #FF0000;
}


Bundled file is here

What am I missing that would cause the styles not to be overridden by the main.scss file?

Answer Source

The issue is in your webpack config options for css-loader. You are using the option for localIdentName which is meant to generate local class names in order to avoid overwriting existing classes; however, your goal is to overwrite the existing bootstrap classes and localization of your classnames is hindering you: localIdentName: '[name]__[local]__[hash:base64:5]'

webpack.config.js (partial view):

        {
            test: /.scss$/,
            use: [
                {
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        modules: true,
                        sourceMap: true,
                        importLoaders: 1
                    }
                },
                {
                    loader: 'sass-loader'
                }
            ]
        },

Additionally, it appears that bootstrap will apply a css rule with higher specificity .navbar-inverse .navbar-brand than the one you have, so your css wouldn't be applied. If you use the same selector in your main.scss, then your style will take precedence and overwrite bootstrap's style:

main.scss

.navbar-inverse .navbar-brand {
    color: #FF0000;
}