User:JDrewniak (WMF)/notes/Understanding mw-ui-icon
@import 'mediawiki.mixins';
@import 'mediawiki.ui/variables';
// Mixins
.mixin-mw-ui-icon-bgimage( @iconSvg, @iconPng ) {
&.mw-ui-icon {
&:before {
.background-image-svg( @iconSvg, @iconPng );
}
}
}
// Icons
//
// To use icons you must be using a browser that supports pseudo elements.
// This includes support for IE 8.
// https://caniuse.com/#feat=css-gencontent
//
// For elements that are intended to have both an icon and text, browsers that
// do not support pseudo-selectors will degrade to text-only.
//
// However, icon-only elements do not yet degrade to text-only elements in these
// browsers.
//
// Styleguide 6.
.mw-ui-icon {
position: relative;
line-height: @iconSize;
min-height: @iconSize;
min-width: @iconSize;
// If an inline element has been marked as a mw-ui-icon element it must be inline-block
span& {
display: inline-block;
}
// Standalone icons
//
// Markup:
// <div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-ok">OK</div><br>
// <div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-ok mw-ui-button mw-ui-progressive">OK</div><br>
// <button class="mw-ui-icon mw-ui-icon-ok mw-ui-icon-element mw-ui-button mw-ui-quiet" title="">Close</button>
//
// Styleguide 6.1.1.
&.mw-ui-icon-element {
@marginIcon: 2 * @iconGutterWidth;
@width: @iconSize + @marginIcon;
@sizeIconLarge: ( @iconSize * 1.75) + @marginIcon;
text-indent: -999px;
overflow: hidden;
width: @width;
min-width: @width;
max-width: @width;
&:before {
left: 0;
right: 0;
position: absolute;
margin: 0 @iconGutterWidth;
}
&.mw-ui-icon-large {
width: @sizeIconLarge;
min-width: @sizeIconLarge;
max-width: @sizeIconLarge;
line-height: @sizeIconLarge;
min-height: @sizeIconLarge;
&:before {
min-height: @sizeIconLarge;
}
}
}
&.mw-ui-icon-before:before,
&.mw-ui-icon-element:before {
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 100% auto;
float: left;
display: block;
min-height: @iconSize;
content: '';
}
// Icons with text
//
// Markup:
// <div class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ok">OK</div>
// <div class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ok mw-ui-progressive mw-ui-button">OK</div>
//
// Styleguide 6.1.2
&.mw-ui-icon-before {
&:before {
position: relative;
width: @iconSize;
margin-right: @iconGutterWidth;
}
}
// Icons small for elements like indicators
//
// Markup:
// <div class="mw-ui-icon mw-ui-icon-small mw-ui-icon-help"></div>
//
// Styleguide 6.1.3
&.mw-ui-icon-small:before {
background-size: 66.67% auto; // 66.67% of 24px equals 16px
}
}
Expected usage
[edit]Standalone icon:
<div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-ok">OK</div>
Icon with text:
<div class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ok">OK</div>
In programming terms, mw-ui-icon
can be thought of as exposing the following interface:
a base class, a modifier class, and an instance property.
The base class is mw-ui-icon
, the modifier class is one of [ mw-ui-icon-before
, mw-ui-icon-element
] and the property is one of many icon image urls mw-ui-icon-{icon name}
.
By themselves, these classes produce nothing. The base class does not have a âdefaultâ state and requires a modifier class to have any effect.
i.e. <div class="mw-ui-icon mw-ui-icon-ok">OK</div>
doesnât work.
The line-by-line
[edit]Now we go through the code above line-by-line and see what we find.
Line #27 .mw-ui-icon
This base class just sizes & positions the box (min-height/min-width/line-height/relative).
.mw-ui-icon {
position: relative;
line-height: @iconSize;
min-height: @iconSize;
min-width: @iconSize;
Line #34 - span&
This guards against a single inline element, <span>
// If an inline element has been marked as a mw-ui-icon element it must be inline-block
span& {
display: inline-block;
}
line #46 - &.mw-ui-icon-element
is a class to create âstand-aloneâ icons. It hides text, overrides the base width, and creates an absolutely positioned :before
pseudo-element.
&.mw-ui-icon-element {
@marginIcon: 2 * @iconGutterWidth;
@width: @iconSize + @marginIcon;
@sizeIconLarge: ( @iconSize * 1.75) + @marginIcon;
text-indent: -999px;
overflow: hidden;
width: @width;
min-width: @width;
max-width: @width;
Line #63 oh! An additional modifier class. &.mw-ui-icon-large
. This resized the icon again (min/max/width and min/line/height).
&.mw-ui-icon-large {
width: @sizeIconLarge;
min-width: @sizeIconLarge;
max-width: @sizeIconLarge;
line-height: @sizeIconLarge;
min-height: @sizeIconLarge;
&:before {
min-height: @sizeIconLarge;
}
}
The expected usage is probably:
<div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-large mw-ui-icon-ok">OK</div>
Line #76 - common rules for mw-ui-icon-before
and .mw-ui-icon-element
. These rules style the :before
pseudo-element which is the container for the actual icon image (placed as a background-image). The min-height of this pseudo-element is declared but the width is not. The width is declared in the modifier classes instead.
&.mw-ui-icon-before:before,
&.mw-ui-icon-element:before {
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 100% auto;
float: left;
display: block;
min-height: @iconSize;
content: '';
}
Line #94 - .mw-ui-icon-before
is a modifier class that accommodates âicons with textâ. Essentially providing a right-margin and relatively positioning the :before
pseudo element (instead of absolutely positioning it like .mw-ui-icon-element
so that the pseudo-element is positioned beside the elements text content.
&.mw-ui-icon-before {
&:before {
position: relative;
width: @iconSize;
margin-right: @iconGutterWidth;
}
}
<span class="icon"></span> text beside element.
Visual Representation
[edit]https://codepen.io/j4n/pen/RwbKMwm