Using nested scss rules in Gatsby scss modules - sass

In React I have a component called GlobalFooter, that provides a website footer.
The component has nested HTML elements.
My scss module looks something like this:
.GlobalSiteFooter {
background-color: #1e6ed0 ;
a.footer-logo {
border: 2px solid #000 ;
img {
}
}
}
When Gatsby processes the component, it adds strings to class names, in order to keep the CSS scoped to the component.
However, it doesn't add a string to the element footer-logo.
It does add a string to the CSS rule 'a.footer-logo'.
As a result, nested rules within SCSS files cannot be applied to their target elements.
As far as the browser is concerned, the targeted elements don't exist.
Is there a way to nest SCSS rules, and have those rules applied to their corresponding DOM elements?

Related

Can you target/ modify existing classes with SCSS Modules?

I'm converting existing SCSS to SCSS Modules in a React app, and I'm having issues targeting classes specified by an external library (react-datepicker in this case).
Using modules changes the classname to something like ._DateField-module__react-datepicker__fWQOd, but is there any way of targeting the DatePicker styles or is this not possible using modules?
Previous Code
DateField.tsx is just a wrapper for DatePicker:
<div className='date-field'>
<DatePicker/>
</div>
DateField.scss successfully overrides existing styles inside the DatePicker component:
.date-field {
...
...
& .react-datepicker {
background-color: $dark-grey;
color: $white;
}
}
You can use :global to switch to global scope for the respective selector.
.date-field {
...
...
:global .react-datepicker {
background-color: $dark-grey;
color: $white;
}
}
You don't need the & there.
Here's a working CodeSandbox.

Sass, create css class dynamic depending on data

I have this class:
.currency-flag-clp:before {
background-image: url('~currency-flags/dist/square-flags/clp.svg');
}
I want to add that class dynamically to an html element, so I need to add a class like:
.currency-flag-XXXXX:before {
background-image: url('~currency-flags/dist/square-flags/XXXXX.svg');
}
Is there a way with sass to do that? I don't want to define 270 class per value, I just want to create the class depending on my data.
As you want to set an individual class on the element it seems you have access to your currency data when building the page. In that case there may be an alternative more simple approach without SASS.
(1) ALTERNATIVE (NON SASS) SOLUTION - maybe a simpler approach
(a) Write a css variable 'actual-currency-flag-url' for your actual flag-image to a style block in the head of your file based on the actual user setting/currency.
(b) Then use that variable to build the url-path in css.
// add to <head> of page:
// based on your data maybe you can do it by php
// note: don't use slashes when building url(...)
<style>
:root {
--actual-currency-url: url(url-path/flag-[actualCurrency].jpg);
}
</style>
// change class off html element
// from <div class="currency-flag-XXXXX"> to:
<div class="currency-flag">
// now you can do in your separate stylesheet file:
.currency-flag:before {
background-image: var(--actual-currency-url);
}
Writing the style direct to the element is less elegant but works as well of course.
(2) POSSIBLE SASS SOLUTION - building 270 classes in SASS using a mixin
(a) Based on your data: generate a simple suffix-list and use it to build a SASS map with the suffixes of your flags.
(b) Use #each to build all 270 classes at once
// example code in SASS:
$flag-suffixes: (
USD,
AUD,
EUR,
//...
);
#each $suffix in $flag-suffixes {
.currency-flag-#{$suffix}:before {
background-image: url('~currency-flags/dist/square-flags/#{$suffix}.svg');
}
}

How to un-nest SCSS

I have a scss file that includes nested styles. The file is intended to end up as the style sheet for Zendesk. Zendesk allows you to use scss like variables, and color functions, however, it does not allow you to use nested style declarations. Is there a way that I can un-nest the styles, while leaving variables and color functions as they are? I have tried looking for a "flatten" function to no avail.
For example:
Input
.footer {
.footer-language-selector {
color: lighten($color_3, 20%);
}
}
Desired Output Note: both the variable and the color function remain as in the input
.footer .footer-language-selector {
color: lighten($color_3, 20%);
}

What is the right way to style an element with multiple selectors in SASS?

I have some elements as such:
<div class="logo">
LOGO HERE
</div>
Considering the a tag is the only element within .logo is it still appropriate to write the SASS as:
.logo {
a {
//STYLES
}
}
Or is normal css ok here? Eg:
.logo a {
//STYLES
}
Both ways work, of course, but is there a preferred way when working with SASS?
Both will work fine in SASS. Traditionally, for readability, it's better to nest the elements, as you've listed in the first example.

Reusing existing span with custom attributes in CKEditor while changing background color

When changing the background-color, CKEditor wraps the selected content in a span element where the inline style is set.
I have an application to create interactive videos: it is possible to stop the playback in desired moments and, in these pauses, the viewer can jump to key moments of the video, or answer to quizzes, returning to specific points of the video if the answer was wrong, and so on. To create this interactive layer above the player I use the CKEditor with some custom plugins to create the interactive elements.
One of the plugins is used to create span elements with a custom attribute data-player-control:
span[data-player-control] {
background-color: #3366FF;
color: #FFF;
border-radius: 10px;
padding: 10px;
}
<span data-player-control="play">My element</span>
The value of the data-player-control attribute is not fixed (it can be specified in the plugin), and it is used to control the exhibition of the video.
When the editor is used to change the element background color, it wraps the element text in a new span, what results in:
span[data-player-control] {
background-color: #3366FF;
color: #FFF;
border-radius: 10px;
padding: 10px;
}
<span data-player-control="play">
<span style="background-color:#FF0000">My element</span>
</span>
These two nested span elements, with two distinct background colors, are undesired.
What I need is the inline style to be applied to the existing span element, resulting in:
span[data-player-control] {
background-color: #3366FF;
color: #FFF;
border-radius: 10px;
padding: 10px;
}
<span data-player-control="play" style="background-color:#FF0000">
My element
</span>
How can this be achieved?
Using dataFilter or htmlFilter is not a feasible solution, as they are executed in input or output data, when entering or existing the inline instance of the CKEditor. Using a transformation also is not a solution, as it uses a simplified form to represent the elements, not the real DOM.
Is there any callback function to use while editing the content (so I can change the DOM according to my needs)?
A simple solution is to listen to the change event in the editor instance and then modify the DOM in event.editor.ui.contentsElement.$ as desired.
You can try to use custom styles definition which is used for adding background-color. The colorButton_backStyle can be set in the editor config.
To override span element with some custom attributes, you can use:
config.colorButton_backStyle = {
element: 'span',
styles: { 'background-color': '#(color)' },
overrides: { 'element': 'span', attributes: { 'data-player-control': 'play' } }
};
So basically overrides attribute is used when applying background-color and there is a span with such attribute - it is replaced (but then the attribute also gets removed ). You can add attributes:
config.colorButton_backStyle = {
element: 'span',
attributes: { 'data-player-control': 'play' },
styles: { 'background-color': '#(color)' },
overrides: { 'element': 'span', attributes: { 'data-player-control': 'play' } }
};
So that overriding span also has your attribute. The problem with this solution is that:
When applying background color to other elements, span will also have data-player-control attribute.
When removing background color, the whole span gets removed.
The above solution may not fit your needs. Maybe there is different approach to the problem you are trying to solve?
As I understand from the question you would like the HTML to have defined structure the whole time (not only as output data), is that correct? What problem is structure with nested spans causing in your application/implementation?

Resources