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.
Related
Syntax error: The hover:rounded-xl class does not exist, but hover:rotate-12 does. If you're sure that hover:rounded-xl exists, make sure that any #import statements are being properly processed before Tailwind CSS sees your CSS, as #apply can only be used for classes in the same CSS
For this, to work you need to enable JIT mode in your tailwind.config.js file
// tailwind.config.js
module.exports = {
...,
mode: "jit",
...
};
I have used a chart library. I want to target and modify the properties of the CSS class generated by that library using external CSS. Let's assume the code in inspector is like this-
<div id="apexcharts9xagqubx" class="apexcharts-canvas apexcharts9xagqubx apexcharts-theme-light" style="width: 319.5px; height: 200px;">
<svg id="SvgjsSvg1001" width="319.5" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" class="apexcharts-svg apexcharts-zoomable hovering-zoom">
<div>
the apex chart documentation says I can target .apexcharts-canvas and change the background color. I have done this:
import React from "react";
import ReactApexChart from 'react-apexcharts'
import './apex.module.css'
return (
<div id="chart">
<ReactApexChart options={data.options} series={data.series} type="area" height={200}/>
</div>
);
inside apex.module.css I did this:
.apexcharts-canvas{
background-color: black;
}
now what?
looks like it doesn't work.
It looks like a CSS specifity thing.
You could try including the parent in the selector:
#chart .apexcharts-canvas {
background-color: black;
}
Hey friend when you import a css file with module prefix you shouldn't import that way, that kind of file will be imported giving it a name for example in this image:
This works equally with css extension files, since I am doing it with scss, this rule is for all css file types.
When you declare with module it's not a global style anymore but a style for a component because there is another way to import it but without the prefix module, in the image I already showed you the name of the declared name and then the name of the class.
Luckily my friend, it is not so complicated, I am also learning this little by little.
IF you are using CSS modules (else let me know):
TL;DR
You can either target the HTML element (instead of its class) where .apexcharts-canvas class is used (option 1), or you can make sure the global CSS imports are compatible with the CSS modules (option 2), checking webpack configuration.
I had same issue, I wanted to edit a CSS class in Apexcharts.
I am assumming you are using CSS modules (.module.css).
Option 1
Use this option if:
you used cra or you do not want to edit webpack configuration
it is enough to target the HTML element instead of the class directly
Steps:
The ID of the div where the chart is should be namespaced (CSS modules): id={styles.chart}, with CSS modules file imported as import styles from 'path-to-file'
In code inspector find div with chart id
Drill down until you find HTML element with your class .apexcharts-canvas
In your CSS modules file, target the HTML element with .apexcharts-canvas, using CSS selectors (example below)
.chart > div > div > :last-child {
background-color: black;
}
Option 2
Use this option if:
you can access the webpack config file (not using cra), AND
you want to target class directly
In the webpack configuration, you need to create a rule not only for CSS modules (import styles from 'path-to-file'), but also for global (normal) CSS (import 'path-to-other-file').
(credit: link)
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
}
}
],
include: /\.module\.css$/
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader'
],
exclude: /\.module\.css$/
},
]
After that you can import a global CSS file (import 'path-to-other-file') with a class .apexcharts-canvas on it.
Important: the webpack rules are mutually exclusive. Files ending with ".module.css" are considered CSS modules, other CSS files not ending like that are global CSS imports.
I'm trying to create custom-element (web component) in svelte 3. I can't find any way to style nested components from css. Svelte removes styles before injecting them to <style> inside of ShadowDOM.
The problem is that I want to have nested components in my root element.
For example:
RootComponent (svelte custom-element)
(imports) FooComponent
(imports) BarComponent
As stated here: svelte-custom-element
All the components imported to custom-element must have compiler option set to <svelte:options tag="component-name" />.
With this option set nested components works as expected and are injected into root's element ShadowDOM. The problem is that styles defined in nested components are not being injected.
The workaround for this problem would be to inject them into root's element <style> as global styles within ShadowDom.
(Un)fortunately svelte automatically removes all unused styles during compilation when custom elements not yet exist.
My goal is to create web component with svelte and then use it outside of svelte as native web-component.
Here is REPL
Custom elements do not really work on REPL as Conduitry wrote:
The compiler options in the REPL don't actually affect the code that >is run, just the code that is displayed. So enabling customElement >doesn't mean you are building and running a web component
So it's more like a code example than working one.
I would like to know if there is another way to create svelte custom-element with nested component and proper styling.
Is there a way to disable removing of unused css?
https://imgur.com/a/zZia566
from <div class="nested"> starts Nested component imported from Nested.svelte.
<style> element should have .nested class injected but it is removed by svelte compiler.
This is because when customElement option is on, each style in a component is injected into the shadowRoot of the custom element.
class YourComponent extends SvelteElement {
constructor(options) {
super();
this.shadowRoot.innerHTML = `<style>.foo{color:red;}</style>`;
// continues
Thus, in order to make style appear, you must use svelte component as custom element, not as svelte component.
Your App.svelte should be like below.
<script>
import Foo from './Foo.svelte'
import Bar from './Bar.svelte'
</script>
<svelte:options tag="web-component" />
<foo-component/>
<bar-component/>
However, this neither solve the problems related with custom element.
:global selector is not transformed into actual global selector.
Every nested component will produce shadowRoot, whereas mostly you will want only top-level one.
Check out some issues below from svelte repository related to custom elements.
nested component in custom element does not inherit style #2605
:global(...) not working in custom elements #2969
It seems like svelte does not fully support style cascading in custom element yet, should be handled in future.
Checked in svelte v3.12.1.
Thanks to brunoalano for sending me this: svelte-custom-element-template. It solves the styling problem with custom build script.
You just have to prevent the compiler from removing unused CSS
Let's say we have a custom element : App.svelte
App.svelte imports a normal svelte component : ./components/Message.svelte
But when you do this, any styles inside Message.svelte will disappear.
Solution
Move all content in the <style> tag of Message.svelte into the <style> tag of App.svelte
Add this to script of App.svelte
let cssKeep: string = "";
Add this to body of App.svelte
<span style="display: none;" class={cssKeep}><span class={cssKeep} /> </span>
This will prevent the compiler from removing any styles
Example
src/components/Message.svelte
<script lang="ts">
export let content: string;
</script>
<p class="red"> {content} </p>
src/App.svelte
<svelte:options tag="my-element" />
<script lang="ts">
import Message from "./components/Message.svelte";
let cssKeep: string = "";
</script>
<Message content="hello" />
<span style="display: none;" class={cssKeep}><span class={cssKeep} /> </span>
<style>
.red {
color: red;
}
</style>
vite.config.ts
import { defineConfig } from 'vite'
import { svelte } from '#sveltejs/vite-plugin-svelte'
export default defineConfig({
build: {
lib: {
entry: './src/main.ts',
name: 'MyElement'
},
},
plugins: [
svelte(
{
compilerOptions: {
css: true,
},
exclude: "./src/App.svelte",
emitCss: true,
}
),
svelte(
{
compilerOptions: {
customElement: true,
css: true,
},
exclude: "./src/components/**",
emitCss: true,
}
),
],
})
// guide: https://www.thisdot.co/blog/web-components-with-svelte
This may answer:
How to export web component in Svelte with nested Svelte components
Use Svelte components with custom elements
Styles missing when Svelte component imported into custom web component / custom element
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.
I am working on building small applications that will live in a website. The website that will host these applications may or may not be using a css framework. I Want to prefix all Bootstrap classes with my own unique prefix.
To avoid "ANY INSTANCE or CHANCE" of conflict I want to prefix all Bootstrap CSS classes with - let's say - "year19-" prefix. So, for example, all the col- classes would now be year19-col- and all the .btn classes would now become .year19-btn, .year19-btn-primary, etc...
I know if I use the sass theme, new classes, then we would get around some of that as we can create our own prefixes using the theming approach, but JS would still remain a source of conflict if two versions of the same framework live on the same page. There was a Github project for Bootstrap 3 with the namespacing feature where you could just add your prefix in the namespace variable then compile the entire code to a CSS and JS package. Bootstrap 4 doesn't seem to have that package yet.
Also, I don't want to wrap the project with a css class. That approach is fine for some things, but not the right approach. I wouldn't even call that namespace. That is just wrapping the classes.
year19-btn-primary {
then this would be whatever the code that already existed there before, not touched.}
I managed to get classes prefixed for Bootstrap 5.1.3. You'll need to make the following changes before compiling Bootstrap yourself. My full implementation is available here: https://github.com/Robpol86/sphinx-carousel/tree/85422a6d955024f5a39049c7c3a0271e1ee43ae4/bootstrap
package.json
"dependencies": {
"bootstrap": "5.1.3",
"postcss-prefix-selector": "1.15.0"
},
Here you'll want to add postcss-prefix-selector to make use of it in postcss.
postcss.config.js
'use strict'
const prefixer = require('postcss-prefix-selector')
const autoprefixer = require('autoprefixer')
const rtlcss = require('rtlcss')
module.exports = ctx => {
return {
map: ctx.file.dirname.includes('examples') ?
false :
{
inline: false,
annotation: true,
sourcesContent: true
},
plugins: [
prefixer({
prefix: 'scbs-', // ***REPLACE scbs- WITH YOUR PREFIX***
transform: function (prefix, selector) {
let newSelector = ''
for (let part of selector.split(/(?=[.])/g)) {
if (part.startsWith('.')) part = '.' + prefix + part.substring(1)
newSelector += part
}
return newSelector
},
}),
autoprefixer({
cascade: false
}),
ctx.env === 'RTL' ? rtlcss() : false,
]
}
}
This is where the CSS will be prefixed. I'm using postcss instead of just wrapping bootstrap.scss with a class/id selector so I can use the Bootstrap 5 carousel component on Bootstrap 4 webpages (which is my use case). This will replace https://github.com/twbs/bootstrap/blob/v5.1.3/build/postcss.config.js
rollup.config.js
// ...
const plugins = [
replace({ // ***COPY/PASTE FOR OTHER BOOTSTRAP COMPONENTS***
include: ['js/src/carousel.js'], // ***YOU MAY NEED TO REPLACE THIS PATH***
preventAssignment: true,
values: {
'CLASS_NAME_CAROUSEL': '"scbs-carousel"', // ***USE YOUR PREFIXES HERE***
'CLASS_NAME_ACTIVE': '"scbs-active"',
'CLASS_NAME_SLIDE': '"scbs-slide"',
'CLASS_NAME_END': '"scbs-carousel-item-end"',
'CLASS_NAME_START': '"scbs-carousel-item-start"',
'CLASS_NAME_NEXT': '"scbs-carousel-item-next"',
'CLASS_NAME_PREV': '"scbs-carousel-item-prev"',
'CLASS_NAME_POINTER_EVENT': '"scbs-pointer-event"',
'SELECTOR_ACTIVE': '".scbs-active"',
'SELECTOR_ACTIVE_ITEM': '".scbs-active.scbs-carousel-item"',
'SELECTOR_ITEM': '".scbs-carousel-item"',
'SELECTOR_ITEM_IMG': '".scbs-carousel-item img"',
'SELECTOR_NEXT_PREV': '".scbs-carousel-item-next, .scbs-carousel-item-prev"',
'SELECTOR_INDICATORS': '".scbs-carousel-indicators"',
}
}),
babel({
// Only transpile our source code
// ...
Lastly rollup replace plugin is used to add the prefixes in the compiled javascript file. I wasn't able to find a way to just prefix the consts so I had to resort to having the entire const replaced and hard-coded with the full class names. This means you'll need to do this for every Bootstrap component that you're including in your final build (for me I just need the carousel so it's not a big deal).