Sass mixin to generate pure CSS hexagon

I had an interview test which in part involved a CSS hexagon, so I wrote a mixin to generate one on the fly.

The mixin in turn requires several other functions (such as to fetch the square root of a number), and because of this I added a math function library to scss-helpers. You can pass up to three colours as a list: first is the default colour, second is :hover and third is :active.

I will write mixins for other polygons when I have the time.

#hexagon {
    @include hexagon(red green blue, 3rem);
@mixin hexagon($colors, $size--width) {
    @if unit($size--width) == '%' {
        // CSS border elements may not use a percentage as its width unit.
        // Hexagon will be malformed if you use a percentage.
        // *Anything* else is acceptable.
        @warn "Percentage #{$ize--width} was used for hexagon width.";
        @warn "Hexagon will be malformed";

    // Rest, hover, active.
    $color--rest: nth($colors, 1);

    // Any measurable unit but percentage is okay!
    $size--width: if(unitless($size--width), to-rem($size--width), $size--width);

    // Sides and height of the hexagon.
    $size--side: $size--width * 0.5;
    $size--height: hex-height($size--side);

    $border--height: $size--height * 0.5;
    $border--width: $size--side * 0.5;

    & {
        // Constrain the background color inside the padding.
        background-clip: content-box;
        display: inline-block;
        height: $size--height;
        padding: 0 $size--side * 0.5;
        position: relative;
        width: $size--side;

        // Center color.
        background-color: $color--rest;
        // :before and :after inherit this.
        border-color: $color--rest;

        &:before, &:after {
            border-color: transparent;
            border-style: solid;
            content: '';
            width: 0;

        @if length($colors) >= 2 {
            $color--hover: nth($colors, 2);

            &:hover {
                background-color: $color--hover;
                border-color: $color--hover;

        @if length($colors) >= 3 {
            $color--active: nth($colors, 3);

            &:active {
                background-color: $color--active;
                border-color: $color--active;

        &:before {
            // Left.
            border-right-color: inherit;
            border-width: $border--height $border--width $border--height 0;
            @include absolute(0 auto 0 0);

        &:after {
            // Right.
            border-left-color: inherit;
            border-width: $border--height 0 $border--height $border--width;
            @include absolute(0 0 0 auto);

Rethinking Sass media queries

A look around told me that most Sass media query solutions fall into the pattern of a mixin that either calls a mixin, or from a list of preset variables. Mine looks like this:

@mixin media($args) {
    $type: nth($args, 1);
    $start: null;
    $end: null;

    @if $type == max {
        // Can't interpolate a mixin, so it becomes a long chain of if/else.
        @include max($start) {

@mixin max($size) {
    // One of many mixins.
    @media screen and (max-width: $size) {

So, three problems:

  1. Preset mixins support only a subset of media queries, usually stuff like max-width, min-height and so on.
  2. Preset variables just aren’t a great solution. It doesn’t encourage variety, and the solution is specific to the project.
  3. Preset units rely on px. Where’s the love for rem or vw? I’d never use them, but still.
  4. A nested mess of mixins or variables is a pain to remember. It becomes a long list of possible values that I have to call in specific order.

I’ve begun a refactor with the idea of passing pithy keywords, in any order, to a mixin. These keywords are parsed into a query condition:

selector {
    @include media(width max 300px, height min 400px) {
        @content 'hello, world';

selector {
    @media only screen and (max-width: 300px) and (min-height: 400px) {
        @content: 'hello, world';

I’ve retained some support for the old mess of mixins in the form of a map that holds preset conditions:

selector {
    @include media(smartphone) {
        @content 'goodbye, world';

selector {
    @media only screen and (min-device-width: 320px) and (max-device-width: 667px) {
        @content: 'goodbye, world';

It’s different, and right now broken-y. It’s working great for simple queries on this site right now, and in the next few days I’ll throw some complex queries at it. GitHub: