2
\$\begingroup\$

I wish to make a mixin to produce the following result of modifier classes:

.text-left {
    text-align: left
}
.text-right {
    text-align: right
}
.text-center {
    text-align: center
}
.text-justify {
    text-align: justify
}
.float-left {
    float: left
}
.float-right {
    float: right
}
.float-none {
    float: none
}
.hide {
    visibility: hidden;
    overflow: hidden;
    max-height: 0
}
.remove {
    display: none
}
@media screen and (max-width: 480px) {
    .m-text-left {
        text-align: left
    }
    .m-text-right {
        text-align: right
    }
    .m-text-center {
        text-align: center
    }
    .m-text-justify {
        text-align: justify
    }
    .m-float-left {
        float: left
    }
    .m-float-right {
        float: right
    }
    .m-float-none {
        float: none
    }
    .m-hide {
        visibility: hidden;
        overflow: hidden;
        max-height: 0
    }
    .m-remove {
        display: none
    }
}
@media screen and (min-width: 481px) and (max-width: 620px) {
    .p-text-left {
        text-align: left
    }
    .p-text-right {
        text-align: right
    }
    .p-text-center {
        text-align: center
    }
    .p-text-justify {
        text-align: justify
    }
    .p-float-left {
        float: left
    }
    .p-float-right {
        float: right
    }
    .p-float-none {
        float: none
    }
    .p-hide {
        visibility: hidden;
        overflow: hidden;
        max-height: 0
    }
    .p-remove {
        display: none
    }
}
@media screen and (min-width: 621px) and (max-width: 955px) {
    .t-text-left {
        text-align: left
    }
    .t-text-right {
        text-align: right
    }
    .t-text-center {
        text-align: center
    }
    .t-text-justify {
        text-align: justify
    }
    .t-float-left {
        float: left
    }
    .t-float-right {
        float: right
    }
    .t-float-none {
        float: none
    }
    .t-hide {
        visibility: hidden;
        overflow: hidden;
        max-height: 0
    }
    .t-remove {
        display: none
    }
}
@media screen and (min-width: 956px) and (max-width: 1199px) {
    .l-text-left {
        text-align: left
    }
    .l-text-right {
        text-align: right
    }
    .l-text-center {
        text-align: center
    }
    .l-text-justify {
        text-align: justify
    }
    .l-float-left {
        float: left
    }
    .l-float-right {
        float: right
    }
    .l-float-none {
        float: none
    }
    .l-hide {
        visibility: hidden;
        overflow: hidden;
        max-height: 0
    }
    .l-remove {
        display: none
    }
}
@media screen and (min-width: 1200px) {
    .d-text-left {
        text-align: left
    }
    .d-text-right {
        text-align: right
    }
    .d-text-center {
        text-align: center
    }
    .d-text-justify {
        text-align: justify
    }
    .d-float-left {
        float: left
    }
    .d-float-right {
        float: right
    }
    .d-float-none {
        float: none
    }
    .d-hide {
        visibility: hidden;
        overflow: hidden;
        max-height: 0
    }
    .d-remove {
        display: none
    }
}

I came up with this mixin, which depends on the media mixin from Neat by thoughtbot.

@mixin respond($responsive-classes) {
    @each $responsive-class in $responsive-classes {
        @each $selector, $rules in $responsive-class {
            $screen: null;
            @if (type-of($rules) == "list") {
                @each $rule in $rules {
                    @include rule-loop($screen, $selector, $rule);
                }
            } @else {
                @include rule-loop($screen, $selector, $rules);
            }
        }
    }
    @each $screen, $query in (
        m: max-width $small-screen,                                 // Phones
        p: min-width $small-screen + 1 max-width $medium-screen,    // Phones to Phablets
        t: min-width $medium-screen + 1 max-width $large-screen,    // Phablets to Tablets
        l: min-width $large-screen + 1 max-width $wide-screen - 1,  // Tablets to Desktops
        d: min-width $wide-screen) {                                // Desktops
        @include media($query, $grid-columns) {
            @each $responsive-class in $responsive-classes {
                @each $selector, $rules in $responsive-class {
                    @if (type-of($rules) == "list") {
                        @each $rule in $rules {
                            @include rule-loop($screen, $selector, $rule);
                        }
                    } @else {
                        @include rule-loop($screen, $selector, $rules);
                    }
                }
            }
        }
    }
}

@mixin rule-loop($screen, $selector, $rules) {
    @each $property, $values in $rules {
        $list: false;
        @if (type-of($values) == "list") { $list: true; }
        @include value-loop($values, $screen, $selector, $property, $list);
    }
}

@mixin value-loop($values, $screen, $selector, $property, $list) {
    @each $value in $values {
        @if $list {
            @if $screen == null {
                .#{$selector}-#{$value} {
                    #{$property}: #{$value};
                }
            } @else {
                .#{$screen}-#{$selector}-#{$value} {
                    #{$property}: #{$value};
                }
            }
        } @else {
            @if $screen == null {
                .#{$selector} {
                    #{$property}: #{$value};
                }
            } @else {
                .#{$screen}-#{$selector} {
                    #{$property}: #{$value};
                }
            }
        }
    }
}

This is how I call it:

@include respond((
  (text: (text-align: (left, right, center, justify))),
  (float: (float: (left, right, none))),
  (hide: ((visibility: hidden), (overflow: hidden), (max-height: 0))),
  (remove: (display: none))
    ));

It got way too complex at some point and I believe it's quite wet. Perhaps someone would be able to dry it out, or have me make a more dry approach to produce the same results? I need the mixin to be dynamic in order to be able to produce more modifier classes, should I need to do so, in the future.

The grid variables are as follows:

// Grid system
$grid-columns: 12;
$sidebar-columns: 4;
$max-width: 1170px;

// Breakpoints
$small-screen: 480px;
$medium-screen: 620px;
$large-screen: 955px;
$wide-screen: 1200px;

You may use #{$query} instead of media($query, $grid-columns) without the Neat mixin. I only used it so that the media queries would combine.

\$\endgroup\$
  • 1
    \$\begingroup\$ It does not compile. Please provide also the values of *-screen variables and the media mixin. Tried on SassMeister. \$\endgroup\$ – fracz Jun 12 '16 at 13:09
  • \$\begingroup\$ @fracz Just updated the question. \$\endgroup\$ – yaharga Jun 12 '16 at 13:29
0
\$\begingroup\$

I ended up with the following mixin that gave me the appropriate results.

Mixin:

// Class Parser
@mixin parse($modifier-classes, $screen) {
    @each $selector, $rules in $modifier-classes {
        @each $property, $values in $rules {
            @if (type-of($values) == "list") {
                @each $value in $values {
                    .#{$screen}#{$selector}-#{$value} {
                        #{$property}: $value;
                    }
                }
            } @else {
                .#{$screen}#{$selector} {
                    #{$property}: $values;
                }
            }
        }
    }
}

// Modifier Classes Mixin
@mixin respond($modifier-classes) {
    @include parse($modifier-classes, null);                            // All
    @each $screen, $query in (
        m: max-width $small-screen,                                     // Phones
        p: min-width $small-screen + 1 max-width $medium-screen - 1,    // Phones to Phablets
        t: min-width $medium-screen max-width $large-screen,            // Phablets to Tablets
        l: min-width $large-screen + 1 max-width $wide-screen - 1,      // Tablets to Desktops
        d: min-width $wide-screen) {                                    // Desktops
        @include media($query) {
            @include parse($modifier-classes, #{$screen}-);
        }
    }
}

Used like so:

// Modifier Classes Variable
$modifier-classes: (
        text:   ( text-align:   (left, right, center, justify)  ),
        float:  ( float:        (left, right, none)             ),
        hide:   ( position:     absolute,
                  overflow:     hidden,
                  clip:         rect(0 0 0 0),
                  height: 1px,  width: 1px,
                  margin: -1px, padding: 0, border:0            ),
        remove: ( display:      none                            )
);

// Modifier Classes Added to CSS
@include respond($modifier-classes);

Gives the following result:

.text-left {
    text-align: left
}
.text-right {
    text-align: right
}
.text-center {
    text-align: center
}
.text-justify {
    text-align: justify
}
.float-left {
    float: left
}
.float-right {
    float: right
}
.float-none {
    float: none
}
.hide {
    position: absolute;
    overflow: hidden;
    clip: rect(0 0 0 0);
    height: 1px;
    width: 1px;
    margin: -1px;
    padding: 0;
    border: 0
}
.remove {
    display: none
}
@media screen and (max-width: 480px) {
    .m-text-left {
        text-align: left
    }
    .m-text-right {
        text-align: right
    }
    .m-text-center {
        text-align: center
    }
    .m-text-justify {
        text-align: justify
    }
    .m-float-left {
        float: left
    }
    .m-float-right {
        float: right
    }
    .m-float-none {
        float: none
    }
    .m-hide {
        position: absolute;
        overflow: hidden;
        clip: rect(0 0 0 0);
        height: 1px;
        width: 1px;
        margin: -1px;
        padding: 0;
        border: 0
    }
    .m-remove {
        display: none
    }
}
@media screen and (min-width: 481px) and (max-width: 619px) {
    .p-text-left {
        text-align: left
    }
    .p-text-right {
        text-align: right
    }
    .p-text-center {
        text-align: center
    }
    .p-text-justify {
        text-align: justify
    }
    .p-float-left {
        float: left
    }
    .p-float-right {
        float: right
    }
    .p-float-none {
        float: none
    }
    .p-hide {
        position: absolute;
        overflow: hidden;
        clip: rect(0 0 0 0);
        height: 1px;
        width: 1px;
        margin: -1px;
        padding: 0;
        border: 0
    }
    .p-remove {
        display: none
    }
}
@media screen and (min-width: 620px) and (max-width: 955px) {
    .t-text-left {
        text-align: left
    }
    .t-text-right {
        text-align: right
    }
    .t-text-center {
        text-align: center
    }
    .t-text-justify {
        text-align: justify
    }
    .t-float-left {
        float: left
    }
    .t-float-right {
        float: right
    }
    .t-float-none {
        float: none
    }
    .t-hide {
        position: absolute;
        overflow: hidden;
        clip: rect(0 0 0 0);
        height: 1px;
        width: 1px;
        margin: -1px;
        padding: 0;
        border: 0
    }
    .t-remove {
        display: none
    }
}
@media screen and (min-width: 956px) and (max-width: 1199px) {
    .l-text-left {
        text-align: left
    }
    .l-text-right {
        text-align: right
    }
    .l-text-center {
        text-align: center
    }
    .l-text-justify {
        text-align: justify
    }
    .l-float-left {
        float: left
    }
    .l-float-right {
        float: right
    }
    .l-float-none {
        float: none
    }
    .l-hide {
        position: absolute;
        overflow: hidden;
        clip: rect(0 0 0 0);
        height: 1px;
        width: 1px;
        margin: -1px;
        padding: 0;
        border: 0
    }
    .l-remove {
        display: none
    }
}
@media screen and (min-width: 1200px) {
    .d-text-left {
        text-align: left
    }
    .d-text-right {
        text-align: right
    }
    .d-text-center {
        text-align: center
    }
    .d-text-justify {
        text-align: justify
    }
    .d-float-left {
        float: left
    }
    .d-float-right {
        float: right
    }
    .d-float-none {
        float: none
    }
    .d-hide {
        position: absolute;
        overflow: hidden;
        clip: rect(0 0 0 0);
        height: 1px;
        width: 1px;
        margin: -1px;
        padding: 0;
        border: 0
    }
    .d-remove {
        display: none
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.