Skip to content

Instantly share code, notes, and snippets.

@kimniche
Last active September 15, 2017 17:28
Show Gist options
  • Save kimniche/d08b79457d6ea2dc6e780d8c2fa418ba to your computer and use it in GitHub Desktop.
Save kimniche/d08b79457d6ea2dc6e780d8c2fa418ba to your computer and use it in GitHub Desktop.

Goal: http://dmv.niche.team/master-774cc/z/new-search/college-ranking.html#

Key Pieces

  • CSS attribute selectors
  • HTML data attributes
  • Less functions (optional)

CSS attribute selectors

  • [attr=value] : element with attr of value
  • [attr^=value] : element with attr beginning with value
  • [attr$=value] : element with attr ending with value
div[class^="link-"] {
  background: gold;
}

a[href$=".org"] {
  color: blue;
}

span[data-meal="breakfast"] {}

span[data-meal="breakfast"][data-food="waffles"] {}

In the Less world... (where & means "use the parent selector here")

div {
  &[class^="link-" {}
}

a {
  &[href$=".org"] {}
}

span {
  &[data-meal="breakfast"] {
    &[data-food="waffles"] {}
  }
}

HTML data attributes

Per MDN:

allow proprietary information to be exchanged between the HTML and its DOM representation by scripts

<img data-id="123" src="foo.png" />

Solution: "collapse windows"

Gist: "collapse windows" are loose breakpoints at which certain suggested topics and their next siblings are made to display: none

What breakpoints?

Very loosely-approximated min-width/max-width windows

How do we know what to collapse and when?

By tracking the total number of preceding label characters for each suggested topic label and adding these as data attributes for each, we can roughly identify in CSS what labels need to collapse at each window

/* SuggestedTopics.jsx */

const SearchTopicsExplorerSuggestedTopics = ({ suggestedTopics }) => {
    let topicsMarkup = [],
        currentCharTotal = 0

    suggestedTopics.forEach(t => {
        const topicMarkup = (<Topic
            key={ t.label }
            analyticsPlacement="Topic-Suggestions"
            topic={ t }
            preceedingLabelsCharTotal={ currentCharTotal }
            />)

        topicsMarkup = [ ...topicsMarkup, topicMarkup ]
        currentCharTotal += t.label.length
    })

    return (
        <ul>
            { topicsMarkup }
        </ul>
    )
}

/* in SearchTopic.jsx */

<li data-char-total={ this.props.preceedingLabelsCharTotal } />

Gotcha: avoid specifying precise number of characters for each collapse window

With the above markup, we could write our Less as something like:

@topics-window-l: ~"only screen and (min-width : 900px) and (max-width : 1082px)";
@topics-window-xl: ~"only screen and (min-width : 1000px) and (max-width : 1300px)";

.search-topics-explorer-list__item {
  &[data-char-total="20"],
  &[data-char-total="21"],
  &[data-char-total="22"],
  // ... ... all the things
    @media @topics-window-l {
      display: none;
  
      ~ .search-topics-explorer-list__item {
          display: none;
      }
    }
    
  &[data-char-total="30"],
  &[data-char-total="31"],
  &[data-char-total="32"],
  // ... ... all the things
    @media @topics-window-xl {
      display: none;
  
      ~ .search-topics-explorer-list__item {
          display: none;
      }
    }
  }
}

Solution: loose groupings of numbers that share a prefix and number of digits

/* in SearchTopic.jsx */

<li 
  data-char-total={ this.props.preceedingLabelsCharTotal }  
  data-char-total-digits={ `${preceedingLabelsCharTotal}`.length }
/>

This lets us target things in CSS by ranges 20-29 total characters preceding, 30-39, 40-49, etc:

.search-topics-explorer-list__item {
    &[data-char-total-digits="2"] {
        &[data-char-total^="2"] {}
        &[data-char-total^="3"] {}
        &[data-char-total^="4"] {}
        // ...

Less functions

Now we (optionally) get really crazy with Less.

We could go with this sort of thing, using a mixin for common handling:

._hide-item-and-next-siblings {
    display: none;

    ~ .search-topics-explorer-list__item {
        display: none;
    }
}

.search-topics-explorer-list__item {
    &[data-char-total-digits="2"] {
        &[data-char-total^="2"] { // total characters of preceeding labels in [20-29]
            @media @topics3 {
                ._hide-item-and-next-siblings();
            }

        }

        &[data-char-total^="3"] { // total characters of preceeding labels in [30-39]
            @media @topics1 {
                ._hide-item-and-next-siblings();
            }

            @media @topics2 {
                ._hide-item-and-next-siblings();
            }

            @media @topics5 {
                ._hide-item-and-next-siblings();
            }
            // ...
        }
    }
}

But we could get even more DRY with a Less function:

._generate-collapse-windows(@breakpoints, @i: 1) when (@i =< length(@breakpoints)) {
    @breakpoint: extract(@breakpoints, @i);

    @media @breakpoint {
        display: none;

        ~ .search-topics-explorer-list__item {
            display: none;
        }
    }

    ._generate-collapse-windows(@breakpoints, (@i + 1));
}

.search-topics-explorer-list__item {
    &[data-char-total-digits="2"] {
        &[data-char-total^="2"] { // total characters of preceding labels in [20-29]
            @collapse-windows: @topics-with-sidebar-sm, @topics-no-sidebar-sm;
            ._generate-collapse-windows(@collapse-windows);
        }

        &[data-char-total^="3"] { // total characters of preceding labels in [30-39]
            @collapse-windows: @topics-no-sidebar-m, @topics-with-sidebar-m, @topics-with-sidebar-l, @topics-no-sidebar-l;
            ._generate-collapse-windows(@collapse-windows);
        }

        &[data-char-total^="4"] { // total characters of preceding labels in [40-49]
            @collapse-windows: @topics-with-sidebar-xl, @topics-no-sidebar-xl;
            ._generate-collapse-windows(@collapse-windows);
        }

        &[data-char-total^="5"] { // total characters of preceding labels in [50-59]
            // NOTE: we never show at this breakpoint, assume too many chars
            @collapse-windows: @topics-with-sidebar-xl-no-max;
            ._generate-collapse-windows(@collapse-windows);
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment