Using CSS attribute selector with styled components for icons - css

I'm using NextJS for React, SSR and styled-components (with hashing). So far I managed to build main CSS structure with Sass.
nextjs.config.js
const withSass = require('#zeit/next-sass')
module.exports = withSass({
cssModules: true,
cssLoaderOptions: {
importLoaders: 1,
localIdentName: "[hash:base64:5]",
}
})
The problem is I cannot use an attribute CSS selector; for icons, usually I define font-family like below
[class^='icon-'] {
font-family: 'fonticon'
}
.icon-foo {
&:before {
content: '\someunicode';
}
}
when I run build and .icon-foo class successfully converts to some hash and match with the CSS. But I cannot use an attribute selector here.
I know it's impossible to convert this kind of selector, but is there any solution, like giving a exception rule for cssLoaderOptions for example,
excludeClasses: /^.icon-/
so I can keep my classes as they are just for the icons?
I know I can give font-family to <i> tag, but I want to avoid that if possible.

Related

Responsive variants for custom configured classes

I've added more padding sizes to my tailwind.config.js. I can access the new padding sizes from my React components, and I can use them in my CSS files. However I can't use the responsive variants in my CSS files like md:p-140 etc.
tailwind.config.js
module.exports = {
theme: {
extend: {
padding: {
'140': '35rem'
}
}
},
// ...
}
I am able to use #apply pb-140 inside my CSS files, but if I use #apply md:pb-140, the class does not exist. The variants work when I use it in a React component, just not in CSS files. The variants for the default classes work with #apply though, like #apply md:p-8.
How can I get variants to work with classes added by my tailwind config?

adding dynamic class name in svelte

I am currently writing an app with svelte, sapper and tailwind. So to get tailwind working I have added this to my rollup config
svelte({
compilerOptions: {
dev,
hydratable: true,
},
preprocess: sveltePreprocess({
sourceMap: dev,
postcss: {
plugins: [
require("tailwindcss"),
require("autoprefixer"),
require("postcss-nesting"),
],
},
}),
emitCss: true,
})
All in all this works, but I am getting some issues with dynamic class names.
Writing something like this always seems to work
<div class={true ? 'class-a' : 'class-b'}>
both class-a and class-b will be included in the final emitted CSS and everything works as expected.
But when I try to add a variable class name it won't work. So imagine this:
<div class={`col-span-6`}>
It will work exactly as expected and it will get the proper styling from the css class col-span-6 in tailwind.
But if I change it to this:
<div class={`col-span-${6}`}>
Then the style won't be included.
If I on the other hand already have a DOM element with the class col-span-6 then the styling will be added to both elements.
So my guess here is that the compiler sees that the css is not used and it gets removed.
And I suppose that my question is then if there is any way to force in all the styling from tailwind? so that I can use more dynamic class names
and not sure if it is relevant but the component I have been testing this on, have this style block
<style>
#tailwind base;
#tailwind components;
#tailwind utilities;
</style>
edit: can add that I am getting a bunch of prints in the log saying that there are unused css selectors that seems to match all tailwind classes
I think it was purgeCSS (built-in in tailwind 2.0) that did not recognize the dynamic classes.
It is difficult to solve this problem for every tailwind classes, but if you don't have a lot of these you can manually safe list those classnames:
// tailwind.config.js
module.exports = {
purge: {
content: ['./src/**/*.html'],
// These options are passed through directly to PurgeCSS
options: {
// Generate col-span-1 -> 12
safelist: [...Array.from({ length: 12. }).fill('').map((_, i) => `col-span-${i + 1}`],
},
},
// ...
}
I think that when the class attribute is a variable or depends on a variable it will not used to extract style during compilation (class-${6} is not evaluated during compilation but during runtime), because svelte marks it as unused css selector because the value of that class attribute is not known when the code is compiled.
To force svelte to include your style you must mark it as global, and to do that we have two options:
<script>
// component logic goes here
</script>
div class={`class-${6}`}/>
option 1:
<style>
:global(.class-6){
// style goes here
}
</style>
option 2: this will mark all your style as global
<style global>
.class-6{
// style goes here
}
</style>
I encounter the same problem, <div class="pl-{indent*4}"> do not work in svelte.
My solution is to use inline style,
<div style="padding-left:{indent}rem">,
which is inferred from pl-1=padding-left: 0.25rem; /* 4px */.
I think it's convenient for simple class.

Remove CSS rule for Material UI component in theme overrides

I want to remove the CSS padding-bottom in the Material UI CardContent component. But I only find solutions on setting it to something else. My current workaround is to set it to something invalid (e.g. -1) so browsers will just ignore it.
I have this theme which contains the workaround:
export default createMuiTheme({
overrides: {
MuiCardContent: {
root: {
"&:last-child": {
paddingBottom: -1,
},
},
},
},
});
would would be the correct way of remove a css rule from a component in Material UI.
(I already tried inherit, initial, revert and unset). Setting it to 0 is not what I want because I want the padding of the MuiCardContent without last-child to get applied.

React/Webpack applying styles to tags but not classes/ids

I have setup my own react project from some tutorials including my own webpack configuration. When I try to style elements it is able to apply style to generic html tags such as <body> or <p> but it fails when I try to style classes/ids.
I know my css file is being imported because it styles the generic tags.
Webpack Config
{
test: /\.css$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{
modules:true
}
}
]
}
CSS
.oakResults {
font-size:20px;
}
#yoyoyo {
color:red;
}
p {
color:orange;
}
React
<div className='oakResults'>
<p id='yoyoyo'>Results</p>
</div>
In my example, the <p> is colored red, but .oakResults font does not change and when I comment out the <p> style it doesn't turn red.
I want it to be able to style to both generic tags and classes/ids.
I think the reason of this issue is you have enable the css modules in webpack but not referring the css correctly.
So if you don't need the css module, try to remove options:{ modules:true} from your webpack config. Then the css could be applied to the class name you set in ReactJS.
Or if you do need the css module, keep the Webpack config. But modify your ReactJS to something like this:
import React, { Component } from 'react';
import styles from 'path\to\file.css';
class foo extend Component {
render() {
return (<div classname={styles.oakResults}> This is the test component</div>)
}
}
Hope it helps.
You should try this,
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
From the docs,
The modules option enables/disables the CSS Modules specification and setup basic behaviour.
Using false value increase performance because we avoid parsing CSS Modules features, it will be useful for developers who use vanilla css or use other technologies.
Refer more about CSS Modules.

Using css-loader inline with Webpack + React

I'm building my React app with Webpack, and css-loader w/modules. I love it. Most of my stylesheets are very small, though, and I'd like to inline them within the same JSX file as my markup and JavaScript.
The CSS loader I'm using right now looks like this:
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
In my JSX, I import my separate CSS files like this:
import classNames from 'dashboard.css';
...
<div className={classNames.foo}></div>;
This is then compiled and translated into something like:
<div class="xs323dsw4sdsw_"></div>
But what I'd like to do is something more like below, while still preserving the localized modules that css-loader gives me:
var classNames = cssLoader`
.foo { color: blue; }
.bar { color: red; }
`;
...
<div className={classNames.foo}></div>;
Is this possible? How can I do this without having to actually require / import a separate file?
I believe your issue is that you your current webpack configuration uses CSS Modules. CSS Modules automatically rename your CSS Classes to avoid global class name collisions.
The fix:
// remove 'modules' from the end of your css-loader argument
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
// like so
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
Now your class names will be preserved. Although, I'm not sure why you want to do this. Do you care to share why?

Resources