Goal: http://dmv.niche.team/master-774cc/z/new-search/college-ranking.html#
- CSS attribute selectors
- HTML data attributes
- Less functions (optional)
[attr=value]
: element withattr
ofvalue
[attr^=value]
: element withattr
beginning withvalue
[attr$=value]
: element withattr
ending withvalue
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"] {}
}
}
Per MDN:
allow proprietary information to be exchanged between the HTML and its DOM representation by scripts
<img data-id="123" src="foo.png" />
Gist: "collapse windows" are loose breakpoints at which certain suggested topics and their next siblings are made to display: none
Very loosely-approximated min-width/max-width windows
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 } />
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"] {}
// ...
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);
}
}
}