Sass deduplicate #imports - css

I'm trying to create two themes for my project. I have following setup:
styles
globals
mixins
helper
themes
Now every theme has an index.scss:
#import "../../mixins/index";
#import "./colors";
#import "./breakpoints";
#import "./typography";
#import "core";
And every theme has a _core.scss:
#if import-once('core.scss') {
:global {
html, body {
background-color: $grey-page-background;
height: 100%;
}
body {
color: $grey-text-primary;
font-family: $font-family-standard;
}
body.page-body.modal-overflow-hidden {
overflow: hidden;
}
.container {
padding: 0;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
width: 100%;
#include breakpoint(large down) {
padding: 0 10px;
}
}
.no-margin {
margin: 0 !important;
}
.text-center {
text-align: center;
}
.green {
color: $green-smava-primary;
}
a:focus, a:hover, a:active {
color: inherit;
}
/* vb = vertical align block, for supporting browser dont support flex-box well */
.vb {
text-align: left;
}
.vb:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
/* vc = vertical align center child, for supporting browser dont support flex-box well */
.vc {
display: inline-block;
vertical-align: middle;
}
.ui.list {
list-style-type: none;
margin: 1em 0;
padding: 0;
.item {
table-layout: fixed;
list-style-type: none;
list-style-position: outside;
padding: .21428571em 0;
line-height: 1.14285714em;
}
}
.ui.list.large {
font-size: 1.14285714em;
}
}
}
As you can see -> index imports core -> and now the theme is imported to the according component (we have a versioning system for components - so this approach is good here).
So a component scss can look like this then:
#import '~styles/theme/smava/index';
.dialog {
&-input {
margin: 0 0 10px 0;
}
&-action {
border-top: 1px solid $grey-shadow-block;
float: right;
}
&-button {
&-pass {
margin-right: 30px;
}
&-login {
margin: 0;
}
}
}
Since I have multiple components core.scss gets imported multiple times.
The problem is, that I need to set a color for the body - this is the reason I have this core.scss.
So how can i deduplicate this? The approach with importing the theme has to stay the same unfortunately.
My stack:
React/Webpack/Redux/Node-sass

Related

merge #extend with parent style and make one class name

I'm trying to merge the style into one class but its showing an error. Look at the example below.
%banner-style{
banner {
padding: 140px 0 210px;
background: url(https://im2.ezgif.com/tmp/ezgif-2-92c6382d82ba.jpg) top center/cover no-repeat;
&.row {
margin: 0;
}
.main-heading {
font-size: 40px;
letter-spacing: -1px;
font-weight: 600;
padding-right: 20px;
sup {
font-size: 10px;
vertical-align: super;
}
}
}
}
And I want it to merge with the parent class .parent
.parent{
color: red;
&_#extend %banner-style;
}
using & to merge into one class name. but showing error unless i do this
.parent{
color: red;
&_{#extend %banner-style};
}
Which is same as if I remove &_.
I wanted .parent_banner {...} but instead got .parent_ banner{...};
Does anyone know how I can accomplish this?
You are getting exactly what is supposed to happen. Extend does not "merge" classes, it extends another class/placeholder into a new selector's styles.
What that means is if I write:
%banner-style {
background: black;
}
.parent {
#extend %banner-style;
}
.other-selector {
#extend %banner-style;
color: red;
}
The css I get will be
.parent {
background: black;
}
.other-selector {
color: red;
background: black;
}
So you are getting expected results. If you'd like to make this "work" the way you want, you can just change your code to:
%banner-style {
padding: 140px 0 210px;
background: url(https://im2.ezgif.com/tmp/ezgif-2-92c6382d82ba.jpg) top center/cover no-repeat;
&.row {
margin: 0;
}
.main-heading {
font-size: 40px;
letter-spacing: -1px;
font-weight: 600;
padding-right: 20px;
sup {
font-size: 10px;
vertical-align: super;
}
}
}
.parent{
color: red;
&_banner {
#extend %banner-style;
};
}
Note: I took out the banner block because it seems you don't want that (and banner isn't a normal html element).

Why my compiled css file's changes not shown on my browser?

My compiled CSS file is hosted locally via Centos5 / Docker on my Mac. And my Less and Css files are on assets/css/ folder.
Once I create less file and first compiled file shown perfectly.
But after I edit less file and compile or edit CSS file, my Chrome does not show my CSS file perfectly.
I trashed Chrome's cache file and opened by another browser (Chromium, Canary, Safari), there was no change.
I tried to serve this on PHP builtin Server on MACOS, it works normally. Think that Docker or CentOS's HTTP server is problem.
You can see actual codes and browser output codes...
Less Codes
#blue: #01569C;
#yellow: #FFE215;
#darkblue: #1A2450;
#socialicon: #54b2df;
#import url(http://fonts.googleapis.com/earlyaccess/notosanskr.css);
body,div,nav,a,p,input {
font-family: 'Noto Sans KR', sans-serif;
color: #blue;
}
body {
background-color: white;
}
// Override Container
.container {
width: 100%;
margin: 0;
padding: 0;
#media (min-width: 1200px){
width: 1200px;
margin: 0 auto;
}
#media (max-width: 1199px){
width: 100%;
}
}
.navbar {
// width: 1200px;
margin: 0 auto;
background-color: white;
color: #blue;
}
.intro-video-container {
max-width: 854px;
margin: 0 auto;
#media(max-width:853px) {
width: 80%;
}
}
.intro {
// width: 1400px;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
* { margin: 0 auto; }
img {
display: block;
margin: 0 auto;
#media (max-width: 1000px) {
width: 100%;
}
}
}
.umr-intro-video {
margin: 10% auto;
}
.btn-social {
color: #socialicon;
}
.bgcircle {
background: #blue url('/assets/images/umr_teaser_2_bg.png') repeat-x top center;
}
.bggraph {
// padding-bottom: 124px;
background: #darkblue url('/assets/images/umr_teaser_5_bg.png') repeat-x bottom center;
}
.bgblue {
background-color: #blue;
}
.bgdarkblue {
background-color: #darkblue;
}
.bgyellow {
background-color: #yellow;
}
.bgwhite {
background-color: white;
}
Compiled CSS Codes
#import url(http://fonts.googleapis.com/earlyaccess/notosanskr.css);body,div,nav,a,p,input{font-family:'Noto Sans KR',sans-serif;color:#01569C}body{background-color:white}.container{width:100%;margin:0;padding:0}#media (min-width:1200px){.container{width:1200px;margin:0 auto}}#media (max-width:1199px){.container{width:100%}}.navbar{margin:0 auto;background-color:white;color:#01569C}.intro-video-container{max-width:854px;margin:0 auto}#media (max-width:853px){.intro-video-container{width:80%}}.intro{width:100%;margin:0;padding:0;overflow:hidden}.intro *{margin:0 auto}.intro img{display:block;margin:0 auto}#media (max-width:1000px){.intro img{width:100%}}.umr-intro-video{margin:10% auto}.btn-social{color:#54b2df}.bgcircle{background:#01569C url('/assets/images/umr_teaser_2_bg.png') repeat-x top center}.bggraph{background:#1A2450 url('/assets/images/umr_teaser_5_bg.png') repeat-x bottom center}.bgblue{background-color:#01569C}.bgdarkblue{background-color:#1A2450}.bgyellow{background-color:#FFE215}.bgwhite{background-color:white}
Browser Output
#import url(http://fonts.googleapis.com/earlyaccess/notosanskr.css);
body,
div,
nav,
a,
p,
input {
font-family: 'Noto Sans KR', sans-serif;
}
body a,
div a,
nav a,
a a,
p a,
input a,
body a:visited,
div a:visited,
nav a:visited,
a a:visited,
p a:visited,
input a:visited,
body a:active,
div a:active,
nav a:active,
a a:active,
p a:active,
input a:active,
body a:hover,
div a:hover,
nav a:hover,
a a:hover,
p a:hover,
input a:hover {
color: #01569C;
}
body {
background-color: #01569C;
}
.container {
width: 100%;
margin: 0;
padding: 0;
}
#media (min-width: 1200px) {
.container {
width: 1200px;
margin: 0 auto;
}
}
#media (min-width: 768px) {
.container {
width: 100%;
}
}
.navbar {
margin: 0 auto;
background-color: white;
color: #01569C;
}
.intro-video-container {
max-width: 854px;
margin: 0 auto;
}
#media (max-width: 853px) {
.intro-video-container {
width: 80%;
}
}
.intro {
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.intro * {
margin: 0 auto;
}
.intro img {
As you see, browser output is broken and shows previous saved version.
Where should I find the reason?
Without more detail it is isn't possible to definately answer your question.
There are a number of possible scenarios, that the server you're working on has caching enabled, in which case you have to work out a strategy for cache busting.
Here's a good article on the subject:
CSS Tricks: Strategies For Cache Busting
Or it could be that your code is not deploying to server when uploading.
If your project is currently in active development, I would recommend that you look into setting up a local development environment, either by configuring a LAMP stack on your development machine, OR using one of the free Software packages like XAMPP or MAMP, once your project is ready for development then deploy it to your server.
(Posted on behalf of the OP).
I stopped using CentOS on Docker and installed Ubuntu 14 on Docker. And configured same setting and it worked.

Inherit CSS class from separate file?

I have a class for a button:
.client-header button {
/*Properties*/
}
and a class to detect when the menu is open:
.client-menu-open {
/*Properties*/
}
I would like to change the button background based on whether or not the menu is open. I want something like this:
.client-header button .client-menu-open {
/*Properties*/
}
But the classes are in two different files, so it doesn't work. Is there any way to do this across different files?
Here is the code for the header index.css:
#import url('../menu/index.css');
.client-header {
position: absolute;
top: 0;
left: 0;
right: 0;
height: var(--header-height);
overflow: hidden;
border-bottom: 1px solid #7E7E7E;
background: #cccccc;
}
.client-header button {
float: left;
height: 100%;
border: none;
border-right: 1px solid var(--border-color);
border-radius: 0;
box-shadow: none;
line-height: 39px;
background-color: #444444;
color: #FFF;
}
.client-header button:hover {
background-color: #555555;
}
.client-header button:active {
background-color: #4E4E4E;
}
.client-header-caption {
float: left;
}
.client-header-title,
.client-header-subtitle {
margin-left: 10px;
}
.client-header-title {
line-height: 25px;
}
.client-header-subtitle {
font-size: 0.5rem;
line-height: 15px;
}
#media (min-width: 640px) {
.client-header-title,
.client-header-subtitle {
display: inline-block;
line-height: var(--header-height);
}
.client-header-title {
font-size: 1.5rem;
}
.client-header-subtitle {
font-size: 1rem;
}
}
.client-header .client-menu-open button {
background: #CCCCCC;
}
And here is the code for the menu index.css:
.client-menu {
position: absolute;
top: var(--header-height);
bottom: 0;
left: -var(--menu-width);
width: var(--menu-width);
border-right: 1px solid var(--border-color);
padding-bottom: var(--menu-footer-height);
overflow: hidden;
transition: left 0.2s;
}
.client-menu-open {
left: 0;
box-shadow: 0 0 30px var(--shadow-color);
background: #444444;
}
.client-menu-pinned {
box-shadow: none;
}
.client-menu-header {
height: var(--menu-header-height);
text-align: right;
background-color: #444444;
}
.client-menu-footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: var(--menu-footer-height);
text-align: right;
}
And the HTML structure is:
<header class="client-header">
<button class="client-header-menu-toggle"/>
</header>
<div class="client-menu"/>
You can use #import like so (in your primary CSS stylesheet):
#import url('external.css');
/* external.css above will be loaded */
Refer to this documentation: http://www.cssnewbie.com/css-import-rule/
Link to the other file and style .client-menu-open
if this is your html
<div class="client-menu-open"> <!-- this class is here only if the menu gets opened, else, this div has no class -->
stuff
stuff
<div class="client-header-button">
<button></button>
</div>
</div>
the correct syntax is the following
button {
background:red;
}
.client-menu-open button {
background:blue
}
The #import rule allows you to include external style sheets in your document. It is a way of creating a style sheet within your document, and then importing additional rules into the document.
To use the #import rule, type:
<style type="text/css">
#import url("import1.css");
#import url "import2.css";
</style>
For more info refer here https://developer.mozilla.org/en-US/docs/Web/CSS/#import
your CSS selector is incorrect, that's why it doesn't work. It has nothing to do with where CSS styles are defined.
.client-header button .client-menu-open will only select the following elements:
elements with class="client-menu-open"
which are children of button elements
which themselves are children of elements with class="client-header"
.
what you want, I think, is
button elements
which are children of elements having "class=client-header" AND "class=client-menu-open".
the proper selector for those elements would be .client-header.client-menu-open button.

Making use of CSS vs Sass (SCSS) - base class issues and redundency

I'm trying to clean up my CSS to be cleaner by using SCSS.
Standard CSS:
.dark-hr,
.light-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
background-color: #595959;
}
.light-hr {
background-color: #cccccc;
}
vs SCSS:
.generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#extend .generic-hr;
background-color: #595959;
}
.light-hr {
#extend .generic-hr;
background-color: #cccccc;
}
Is there any way to avoid creating the 'generic-hr' class that won't be used? I was hoping that some kind of nest would work well.
In this scenario the CSS is definitely way cleaner and more readable than SCSS.
Ideally I would need this to work in SCSS:
.## {
// base class that is not outputted
.dark-hr {
//attributes the extend the base class '.##'
}
.light-hr {
//attributes the extend the base class '.##'
}
}
OUTPUT:
.dark-hr, .light-hr {
//shared attributes defined by '.##'
}
.dark-hr {
// overrides
}
.light-hr {
// overrides
}
What you're wanting to use is an extend class (I call them "silent classes"), which is signified by using a % instead of a ..
hr%base {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#extend hr%base;
background-color: #595959;
}
.light-hr {
#extend hr%base;
background-color: #cccccc;
}
Wouldn't you normally do something like this:
.generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
&.dark {
background-color: #595959;
}
&.light {
background-color: #cccccc;
}
}
My pattern for this kind of thing is a mixin:
#mixin generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#include generic-hr;
background-color: #595959;
}
.light-hr {
#include generic-hr;
background-color: #cccccc;
}
This has the added advantage of being extensible, so if you find yourself needing several selectors with really similar properties you can add in variables:
#mixin generic-hr($background-color: transparent) {
width: 100%;
height: 1px;
margin: 15px 0px;
background-color: $background-color;
}
.dark-hr {
#include generic-hr(#595959);
}
.light-hr {
#include generic-hr(#cccccc);
}
.medium-hr {
#include generic-hr(#818181);
}

#import in #if statement in Sass

I want to load only the css needed for the login page for performance. On my other pages I want a grouped css file that will be cached on every page which contain all my css.
I have the following files:
minifiedcssforloginpage.scss
grouped-pages.scss
In minifiedcssforloginpage.scss I declare $load-complete-css:false. Afterwards I import myproject.scss which contains all the imports of my modules, layouts, core... In myproject.scss i want to do something like
#if $load-complete-css {
#import module1;
#import module2;
#import module3;
}
So minifiedcssforloginpage.scss would generate minifiedcssforloginpage.css with less css then grouped-pages.css (that has a var $load-complete-css set to true).
But I get an error that this is not possible "Import directives may not be used within control directives or mixins".
It's one of those things that's just not allowed. The only thing you can do is turn those imports into mixins (import the file outside the #if and call the mixin where appropriate).
Clarification:
_partial.scss
#mixin partial {
.test { color: red }
// other styles here
}
styles.scss
#import "partial";
#if $someval == true {
#include partial;
}
The core dev team is reluctant to implement this feature, although they are considering the implementation of a brand new dependency system.
See the following Github issues :
Allow #import within #if (#451)
Using #import statements within control directives or mixins (#779)
Allow optional #imports (#779)
Dynamic Dependencies (#739)
Put your styles into various partial files in a way that makes sense to you. Then, you can have create a separate SASS file for your login page that imports only the files with the relevant styles.
To quote from my answer to another question:
It is currently not possible to use SASS to include files dynamically.
#import cannot be used within control directives (e.g. #if) or
mixins, using a variable in an import directive is erroneous syntax,
and there is no directive for ending file execution early (which
effectively would allow conditional imports). However, you can
solve your issue by changing how you structure your style rules.
... If you have styles that [should be] conditionally included [they]
should be encapsulated in mixins, in 'module' or 'library' files. ...
The main idea is that importing one such file will not output any
css. This way, you can import these files redundantly so you can use
the mixins wherever you need them.
There isn't currently a way to place import statements within if blocks, unfortunately.
The closest alternative I'm aware of is to use the additionalData field to add a preprocessor function to your webpack sass-loader config:
{
loader: "sass-loader",
options: {
sassOptions: {
includePaths: [...],
},
additionalData: (content: string, loaderContext)=>{
// More info on available properties: https://webpack.js.org/api/loaders
const {resourcePath, rootContext} = loaderContext;
const finalPath = someCondition ? path1 : path2;
return content.replace(/SomeDynamicPathPlaceholder/g, finalPath);
},
},
},
More info on the additionalData field here: https://webpack.js.org/loaders/sass-loader/#additionaldata
I know this is a seriously old question, but we recently implemented this in our own tiny UI framework like this:
ui-framework/config.scss
$components: (
"component-a": true,
"component-b": false
) !default;
// A bunch of other default config
ui-framework/main.scss
#import "component-a";
#import "component-b";
ui-framework/component-a.scss
#if (map-get($components, "component-a") {
.component-a {
// Bunch of code here
}
}
ui-framework/component-b.scss
#if (map-get($components, "component-b") {
.component-b {
// Bunch of code here
}
}
And then in each project:
a-project/main.scss
// NOTE: We only want component b in this project
$components: (
"component-a": false,
"component-b": true
);
#import "ui-framework/config.scss";
#import "ui-frameowrk/main.scss";
We don't do this for every single component, but the huge ones that aren't always in use (like slideshow, dialog, form related code etc).
Old question, I know; just felt I'd provide an alternative scenario and expanded example based on something I was working on.
I ran into this issue because I was hoping to use one SCSS file for smaller screens and one for larger (top menu nav on desktop and burger menu for mobiles).
Using Blazor without Bootstrap, I was wanting to use the one menu structure in terms of the actual html and then use the SCSS to switch between the two at the relevant sizes. I'd created a SCSS file for the desktop version of the nav, and started on one for the mobile version. My plan, before I was aware of this stumbling block, was to selectively import the SCSS based on a media query in a mixin (aptly named mobileOrDesktop).
My idea was to use this mixin to do all the base structure manipulation for the media sizes. Something like this:
#mixin mobileOrDesktop {
#media (min-width: 961px) {
#import 'desktopNavbar.scss';
.container-fluid {
margin-top: 70px;
height: calc(100% - calc(60px + 70px));
}
//show the footer, maybe tweak the font size, etc
}
#media (max-width:960px) {
#import 'moblieNavbar.scss';
.container-fluid {
height: 100%;
}
//hide the footer, maybe tweak font sizes, etc
}
}
Unfortunately, we can't do that due to how SCSS works. So, rather than just dumping all the CSS in the media query (I wanted to keep it relatively split up so that it was more manageable for debug/altering), I had a hunt for alternatives.
Similarly to Cinnamon, I found the most viable solution to be importing the SCSS outside of the mixin and simply including it within the mixin:
#import 'desktopNavbar.scss';
#import 'mobileNavbar.scss';
#mixin mobileOrDesktop {
#media (min-width: 961px) {
#include desktopNavbar;
.container-fluid {
margin-top: 70px;
height: calc(100% - calc(60px + 70px));
}
}
#media (max-width:960px) {
#include moblieNavbar;
.container-fluid {
height: 100%;
}
}
}
With the imported SCSS files being a mixin themselves, i.e. the desktopNavbar.scss becomes:
#import 'siteVariables.scss';
#mixin desktopNavbar {
#navbar {
.burgerIcon {
display: none;
}
.nav {
overflow: hidden;
background-color: $navy;
vertical-align: middle;
height: 70px;
line-height: 70px;
color: $blizzard;
position: fixed;
top: 0;
width: 100%;
display: block;
z-index: 99999999;
.leftBlock, .midBlock, .rightBlock {
display: inline-block;
vertical-align: middle;
height: 70px;
padding: 0px;
margin: 0px;
line-height: 70px;
}
.leftBlock {
width: 20%;
.imgLogo {
margin-left: 10px;
margin-top: 5px;
max-width: 120px;
}
}
.midBlock {
width: 60%;
text-align: center;
.navbar-nav {
display: inline-flex;
flex-wrap: nowrap;
flex-grow: 2;
flex-shrink: 2;
list-style: none;
vertical-align: middle;
margin: 0px;
padding: 0px;
.nav-item {
max-width: 175px;
color: $white;
display: inline-block;
vertical-align: middle;
height: 70px;
.btn-link {
font-size: 16px;
text-align: right;
color: $white;
padding: 14px;
line-height: 20px;
text-decoration: none;
vertical-align: middle;
span {
font-family: 'Font Awesome Solid';
line-height: 60px;
height: 60px;
vertical-align: middle;
padding: 5px;
}
}
&.dropdown {
font-size: 16px;
text-align: right;
line-height: 20px;
text-decoration: none;
vertical-align: middle;
.dropbtn {
font-size: 16px;
text-align: right;
line-height: 20px;
text-decoration: none;
vertical-align: middle;
span {
font-family: 'Font Awesome Solid';
line-height: 60px;
height: 60px;
vertical-align: middle;
padding: 5px;
}
}
.dropdown-content {
display: none;
position: fixed;
top: 68px;
text-align: center;
background-color: $star-command;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 99999999999;
.dropdown-header {
color: $blizzard;
}
.dropdown-item {
color: $powder;
padding: 12px 16px;
text-decoration: none;
display: block;
&:hover {
background-color: $blizzard;
color: $navy;
}
}
}
&:hover {
background-color: $star-command;
.dropdown-content {
display: block;
}
}
}
}
}
}
.rightBlock {
width: 20%;
}
}
}
}
And the site SCSS can simply be:
#import '../../FontAwesome/scss/fontawesome.scss';
#import '../../FontAwesome/scss/regular.scss';
#import '../../FontAwesome/scss/solid.scss';
#import 'siteVariables.scss';
#import 'mixins.scss';
//import other stuff here
html, body {
height: 100%;
overflow: hidden;
width: 100%;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif !important;
margin: 0px;
#include mobileOrDesktop;
.container-fluid {
overflow: auto;
main {
padding: 15px;
}
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
.dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
}
}

Resources