@import in @if statement in Sass
Asked Answered
C

6

40

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".

Contraption answered 14/12, 2012 at 12:49 Comment(2)
You do understand, however, that SASS is not dynamic, right? Once it is compiled, that's it. There's no state changes or anything like that. You can't set $loggedin to true once the user has logged in because the CSS is already compiled.Circumscription
Yes, it was a bad naming. I changed itContraption
C
45

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;
}
Circumscription answered 14/12, 2012 at 13:11 Comment(6)
You mean like @if $load-complete-css { @include othercomponents; } @mixin othercomponents { @import "module1" ; @import "modules2"; } ? I have now the same error.. It's not possible to import in a mixin eitherContraption
Correct: the mixin in question cannot perform an import either. You have to place the entire contents of your files into a single mixin if you want to use it with @if.Circumscription
Ok so i think it would be better to make 2 sass project files myproject-full-modules.scss with all imports of all the modules and myproject-basics.scss with the essential modules the problem is, it's not DRY: If I want to disable a module I have to remove it on 2 filesContraption
How much styling is there that's exclusive to one page? Splitting up the files and causing 2 HTTP requests is probably worse than having a single file that includes everything.Circumscription
@Circumscription Or not. Smaller files are independently cacheable. Two HTTP requests is no problem if one or the other file will be cached for future page loads. I tend to believe that the current fad of concatenating all CSS and JS for the whole site is very poor practice, caused by a failure to think about how to properly modularize.Acquittance
I'm pretty stoked on this solution -- really clever thinking thank you!Anglia
W
16

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 :

Wagonette answered 30/3, 2014 at 12:28 Comment(5)
Do you know why they are reluctant? This functionality would be extremely helpful for me right now.Trimetrogon
@Trimetrogon : You might want to take a look at and contribute to the discussion that has been going on @ Github (see links hereabove). The more people request this feature, they more likely they'll eventually implement it ;-)Wagonette
Yeah, I did. And that's the key, "eventually". Probably won't happen. I saw something about them building some kind of new dependency management system. But that was three years ago. Doesn't look like anything is actually happening. So I just didn't really see the point. :)Trimetrogon
@Trimetrogon : Their inability to relate with what their users actually need and their unwillingness to implement features as important as dynamic dependencies have been bothering me for a long time, to the point where I actually considered writing my own preprocessor language... It sucks, but I guess we just have to live with if if we want to keep using Sass...Wagonette
indeed. Still prefer it to plain CSS, though haha.Trimetrogon
F
7

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.

Formalism answered 15/1, 2014 at 21:41 Comment(0)
V
3

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

Velarde answered 19/8, 2020 at 16:58 Comment(0)
F
1

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).

Felisafelise answered 14/9, 2021 at 21:2 Comment(0)
T
-1

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;
        }
    }
}
Trace answered 2/12, 2021 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.