Skip to content

Instantly share code, notes, and snippets.

@joaocunha
Created December 11, 2014 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save joaocunha/acb14dafbdfadf75e5dd to your computer and use it in GitHub Desktop.
Save joaocunha/acb14dafbdfadf75e5dd to your computer and use it in GitHub Desktop.
Stylus Mixins used on the MDN Kuma project
@require 'vars';
@require 'prefixes';
/*
Provides man mixins for use within the MDN theme.
*/
/* searches expression for the provided string and replaces with provided value */
replace($expr, $str, $val) {
$expr = clone($expr);
for $e, $i in $expr {
if ($e == $str) {
$expr[$i] = $val;
}
}
return $expr;
}
set-font-size(value) {
font-size: value;
if (value is not inherit) {
// make sure we're working with px otherwise remify will just spit out what we spat out before */
u = unit(value);
if (u is 'px') {
font-size: remify(value);
}
}
}
remify(value) {
u = unit(value);
if (u is 'px') {
return unit(value/$base-font-size, 'rem')
} else {
return unit(value, u)
}
}
set-smaller-font-size() {
set-font-size($smaller-font-size);
}
set-larger-font-size() {
set-font-size($base-bump-font-size);
}
/* vendor prefixes */
/* vendorizes a propery based on it's value in the prefixes.styl lookup table */
vendorize($property, $value) {
$prefixes = $prefix-properties[''+$property];
// might be a quoted because it has commas in it, example: transition-property
if($value is a 'string' or $value is a 'ident') {
$value = unquote($value);
}
if($prefixes == null) {
// warn if we're prefixing something unrecognized.
warn('Warning in vendorize(): ' + $property + ' not listed in prefixes.styl')
// provide unprefixed value as fallback
$property: $value;
} else {
for $prefix in $prefixes {
{$prefix + $property}: $value;
}
// warn if we're vendorizing something unneccisarily
if($prefixes == '') {
warn('Warning in vendorize() ' + $property + ' does not need to be vendorized anymore. ')
}
}
}
/* vendorizes a value indescriminately by adding the prefixes defined by VENDOR-PREFIXES */
vendorize-value(property, value, more = '') {
for prefix in VENDOR-PREFIXES {
{property}: unquote(prefix + value + more);
}
{property}: unquote(value + more);
}
/* prevents spacing of a given element if it's the last child */
prevent-last-child-spacing(element = '*', property = 'padding') {
if (element is '*') {
element = unquote(element);
}
& > {element}:last-child {
{property}: 0;
}
}
prevent-last-child-bottom-spacing(element = '*') {
prevent-last-child-spacing(element, margin-bottom);
prevent-last-child-spacing(element, padding-bottom);
}
/* text-decoration none, hover text-decoration underline */
reverse-link-decoration() {
a {
text-decoration: none;
&:hover, &:active, &:focus {
text-decoration: underline;
}
}
}
/* converts an rgba value to hex, blending on white or the provided background hex/rgb (must provide flat colour for background) */
rgba-to-hex($color, $bg = #fff) {
if(typeof($color) == 'rgba') {
$a = alpha($color);
$fallback = $color * $a + $bg * (1 - $a);
return $fallback;
} else {
error('rgba-to-hex() must be used passed an rgba value');
}
}
/* creates a hex fallback of a property using an rgba value
will use white as the background matte if no colour is provided
example input: .test { border: 20px solid rgba-fallback(rgba(255,0,0,0.5), #000);}
example output: .test { border: 20px solid #800000; border: 20px solid rgba(255,0,0,0.5); }
*/
rgba-fallback($color, $bg = #fff) {
// check mixin was called inside a property
if (current-property) {
// check mixin was passed an rgba
if(typeof($color) == 'rgba') {
// get value of property
$val = current-property[1];
// create our fallback hex
$fallback-hex = rgba-to-hex($color, $bg);
// replace the rgba with the hex in the value of the property
$hex-val = replace($val, '__CALL__', $fallback-hex);
// add a duplicate property with the fallback value
add-property(current-property[0], $hex-val);
} else {
error('rgba-fallback() must be given an rgba value');
}
// return the rgba for use in the original property
$color
} else {
error('rgba-fallback() must be used within a property');
}
}
/* generates a background property for header and zones */
create-gradient-background(color = '', use-gradient = false) {
if use-gradient {
background-image: url($media-url-dir + 'header-background.png'), url($media-url-dir + 'mdn-header-gradient.png');
background-repeat: repeat, repeat-x;
} else {
background-image: url($media-url-dir + 'header-background.png');
background-repeat: repeat;
}
background-position: 0 0, 0 0, 0 0;
if color {
background-color: color;
}
}
create-home-gradient-background(color) {
create-gradient-background(color);
background-image: url($media-url-dir + 'header-background.png'), url($media-url-dir + 'blueprint.png'), url($media-url-dir + 'mdn-header-gradient.png');
background-repeat: repeat, repeat, repeat-x;
}
/* generates a cross-browser gradient */
create-gradient(start-color, end-color, direction = false) {
if direction {
vendorize-value(background, linear-gradient, '(' + direction + ', ' + start-color + ', ' + end-color + ')');
} else {
vendorize-value(background, linear-gradient, '(' + start-color + ', ' + end-color + ')');
}
filter: unquote("progid:DXImageTransform.Microsoft.gradient(startColorstr='" + start-color + "', endColorstr='" + end-color + "', GradientType=1)"); /* IE6-9 */
}
/* generates the essential "before" and "after" code for pseudo-arrows */
generate-arrow(arrow-width = 10px) {
&:before, &:after {
content: ' ';
height: 0;
position: absolute;
width: 0;
border: arrow-width solid transparent;
}
}
/* used to create sliding animations */
slider(duration=$default-animation-duration, maximum-height = 10000px) {
overflow-y: hidden;
max-height: maximum-height;
vendorize(transition-property, all);
vendorize(transition-duration, duration);
vendorize(transition-timing-function, $slide-timing-function);
&.closed {
max-height: 0;
}
}
/* sets the base styles for messages (review, warning, error, notice, etc.) */
set-message-base(remove-last-spacing = true) {
border-width: 5px;
border-style: solid;
padding: ($grid-spacing / 2);
margin-bottom: $grid-spacing;
set-smaller-font-size();
if(remove-last-spacing) {
& *:last-child {
margin-bottom: 0;
padding-bottom: 0;
}
}
}
/* removes the implied "<main>" spacing so page is more customizable */
remove-main-spacing() {
main > .center {
width: auto;
padding: 0;
margin: 0;
max-width: none;
}
}
add-center-spacing(spacing = $gutter-width) {
padding-left: spacing;
padding-right: spacing;
}
remove-center-spacing() {
padding-left: 0;
padding-right: 0;
}
/* overrides the navigation menu color - zones and homepage */
override-main-nav-color(hex) {
#main-nav > ul > li > a,
.user-state,
.user-state a,
.submenu-close {
color: hex;
}
#main-nav > ul > li {
.search-wrap {
background-color: rgba-fallback(rgba(255, 255, 255, 0.4));
input, i, .search-trigger {
color: hex !important;
}
input {
set-placeholder-style(color, hex);
}
}
}
}
/* overrides the size of the navigation search box on certain pages */
minimize-header-search() {
.main-nav-search {
width: 36px;
@media $media-query-mobile {
width: auto;
}
}
.search-wrap input {
width: 22px;
&:focus {
width: 500px;
}
}
}
/* sets an input tag's placeholder styles */
set-placeholder-style(prop, value) {
&::-webkit-input-placeholder {
{prop}: value;
}
&::-moz-placeholder {
{prop}: value;
}
}
/* uses the white logo instead of color logo */
use-white-logo() {
#main-header .logo {
background-position: 0 -41px;
}
}
/* for use */
/*
Allows setting of a property for LTR and RTL without having to deal with duplicating and maintaining selectors:
example: bidi-style(left, 20px, right, auto)
*/
bidi-style(ltr-prop, value, inverse-prop, inverse-value, make-important = false) {
make-important = make-important ? unquote('!important') : unquote('');
{ltr-prop}: value make-important;
html[dir='rtl'] & {
if (ltr-prop != inverse-prop) {
{inverse-prop}: value make-important;
}
{ltr-prop}: inverse-value make-important;
}
}
bidi-value(prop, ltr, rtl, make-important = false) {
bidi-style(prop, ltr, prop, rtl, make-important);
}
bidi-value-vendorize(prop, ltr, rtl, make-important = false) {
make-important = make-important ? unquote('!important') : unquote('');
vendorize(prop, ltr make-important);
html[dir='rtl'] & {
vendorize(prop, rtl make-important);
}
}
/*
MIXINS LIKE CLASSES
These are not dynamic but serve as mixins so that styles wont be repeated throughout files
*/
heading-1() {
set-font-size(($content-block-margin * 2));
letter-spacing: -2px;
}
heading-2() {
set-font-size(30px);
letter-spacing: -1px;
}
big-search() {
background: rgba-fallback(rgba(255, 255, 255, 0.2));
set-larger-font-size();
display: block;
margin: 0 auto;
border: 0;
border-radius: 3px;
font-family: $heading-font-family;
width: 60%;
}
offscreen() {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
clearfix() {
clear:both;
&:after {
content: ' ';
clear: both;
display: table;
}
}
title-header() {
font-weight: bold;
text-transform: uppercase;
color: $text-color;
text-decoration: none;
display: block;
}
/* submenu generator: used in the main navigation and wiki */
component-submenu(menu-width, num-columns, background-color, arrow-border-color) {
position: absolute;
padding: $grid-spacing;
background: background-color;
display: none;
width: menu-width;
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.4);
component-submenu-close();
.submenu-column {
if num-columns is 1 {
col-width = 100%;
} else {
col-width = ((menu-width - (num-columns * $grid-spacing) - 1) / num-columns) + ($grid-spacing / 2);
}
vertical-align: text-top;
width: col-width;
display: inline-block;
&:nth-child(even) {
bidi-style(border-left, 1px dotted #d4dde4, border-right, 0);
bidi-style(padding-left, $grid-spacing, padding-right, 0);
}
}
a {
set-smaller-font-size();
padding: 5px 0;
display: block;
}
reverse-link-decoration();
generate-arrow();
&:before {
border-bottom-color: background-color;
position: absolute;
z-index: 2;
}
&:after {
border-bottom-color: arrow-border-color;
position: absolute;
z-index: 1;
}
@media $media-query-mobile {
.submenu-column, .submenu-column:nth-child(even) {
bidi-style(border-left, 0, border-right, 0);
bidi-style(padding-left, 0, padding-right, 0);
}
}
@media $media-query-small-mobile {
& {
width: auto;
.submenu-column {
width: auto;
display: block;
}
}
}
}
component-submenu-close() {
.submenu-close {
display: none;
position: absolute;
top: 20px;
bidi-style(right, 0, left, auto);
i {
margin-left: 0;
}
}
@media $media-query-tablet {
.submenu-close {
display: block;
}
}
}
/* When an element contains a label and a checkbox in order (as on the edit
profile page and elsewhere) make them appear on the same line, with the
checkbox to the left of the label. */
$checkbox-label-container {
clearfix();
input[type='checkbox'] {
bidi-value(float, left, right);
}
label {
position: absolute;
bidi-style(margin-left, 25px, margin-right, 0);
}
}
/* Dropdown menus that hide advanced feature, such as the "This Page" menu on
article pages, the "Advanced" menu on profiles, etc. */
$advanced-menu {
component-submenu(160px, 1, $button-background, $button-shadow-color);
bidi-style(right, 0, left, auto);
top: 40px;
z-index: 3;
border-top: 1px solid $button-shadow-color;
width: 160px !important; /* needs this due to overriding media query rule of component */
bdi {
bidi-value(text-align, left, right);
}
&:before {
bidi-style(right, 10px, left, auto);
top: -18px;
}
&:after {
bidi-style(right, 10px, left, auto);
top: -20px;
}
}
$right-icons {
margin-left: 0 !important;
margin-right: 10px !important;
}
/* Styles for code blocks - used for wiki document and WYSIWYG editor */
$code-block {
background: $code-block-background-color;
border-left: 6px solid $code-block-border-color;
background-image: url($media-url-dir + 'blueprint-dark.png');
background-position: top center;
background-repeat: repeat;
vendorize(tab-size, 4);
vendorize(hyphens, none);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment