1 | // Foundation for Sites by ZURB
|
2 | // foundation.zurb.com
|
3 | // Licensed under MIT Open Source
|
4 |
|
5 | ////
|
6 | /// @group functions
|
7 | ////
|
8 |
|
9 | /// Creates an inner box-shadow for only one side
|
10 | ///
|
11 | /// @param {Keyword} $side - Side the shadow is supposed to appear. Can be `top`, `left`, `right` or `bottom`.
|
12 | /// @param {Number} $size - Width for the target side.
|
13 | /// @param {Color} $color - Color of the shadow.
|
14 | @mixin inner-side-shadow(
|
15 | $side: bottom,
|
16 | $size: 20px,
|
17 | $color: rgba($black, 0.25)
|
18 | ) {
|
19 |
|
20 | $helper: round($size * 0.65);
|
21 |
|
22 | @if ($side == top) {
|
23 | box-shadow: inset 0 $helper $size (-1)*$helper $color;
|
24 | } @else if ($side == left) {
|
25 | box-shadow: inset $helper 0 $size (-1)*$helper $color;
|
26 | } @else if ($side == right) {
|
27 | box-shadow: inset (-1)*$helper 0 $size (-1)*$helper $color;
|
28 | } @else if ($side == bottom) {
|
29 | box-shadow: inset 0 (-1)*$helper $size (-1)*$helper $color;
|
30 | }
|
31 | }
|
32 |
|
33 | /// Creates a CSS triangle, which can be used for dropdown arrows, dropdown pips, and more. Use this mixin inside a `&::before` or `&::after` selector, to attach the triangle to an existing element.
|
34 | ///
|
35 | /// @param {Number} $triangle-size - Width of the triangle.
|
36 | /// @param {Color} $triangle-color - Color of the triangle.
|
37 | /// @param {Keyword} $triangle-direction - Direction the triangle points. Can be `up`, `right`, `down`, or `left`.
|
38 | @mixin css-triangle(
|
39 | $triangle-size,
|
40 | $triangle-color,
|
41 | $triangle-direction
|
42 | ) {
|
43 | display: block;
|
44 | width: 0;
|
45 | height: 0;
|
46 |
|
47 | border: inset $triangle-size;
|
48 |
|
49 | content: '';
|
50 |
|
51 | @if ($triangle-direction == down) {
|
52 | border-bottom-width: 0;
|
53 | border-top-style: solid;
|
54 | border-color: $triangle-color transparent transparent;
|
55 | }
|
56 | @if ($triangle-direction == up) {
|
57 | border-top-width: 0;
|
58 | border-bottom-style: solid;
|
59 | border-color: transparent transparent $triangle-color;
|
60 | }
|
61 | @if ($triangle-direction == right) {
|
62 | border-right-width: 0;
|
63 | border-left-style: solid;
|
64 | border-color: transparent transparent transparent $triangle-color;
|
65 | }
|
66 | @if ($triangle-direction == left) {
|
67 | border-left-width: 0;
|
68 | border-right-style: solid;
|
69 | border-color: transparent $triangle-color transparent transparent;
|
70 | }
|
71 | }
|
72 |
|
73 | /// Creates a menu icon with a set width, height, number of bars, and colors. The mixin uses the height of the icon and the weight of the bars to determine spacing. <div class="docs-example-burger"></div>
|
74 | ///
|
75 | /// @param {Color} $color [$black] - Color to use for the icon.
|
76 | /// @param {Color} $color-hover [$dark-gray] - Color to use when the icon is hovered over.
|
77 | /// @param {Number} $width [20px] - Width of the icon.
|
78 | /// @param {Number} $height [16px] - Height of the icon.
|
79 | /// @param {Number} $weight [2px] - Height of individual bars in the icon.
|
80 | /// @param {Number} $bars [3] - Number of bars in the icon.
|
81 | @mixin hamburger(
|
82 | $color: $black,
|
83 | $color-hover: $dark-gray,
|
84 | $width: 20px,
|
85 | $height: 16px,
|
86 | $weight: 2px,
|
87 | $bars: 3
|
88 | ) {
|
89 | // box-shadow CSS output
|
90 | $shadow: ();
|
91 | $hover-shadow: ();
|
92 |
|
93 | // Spacing between bars is calculated based on the total height of the icon and the weight of each bar
|
94 | $spacing: ($height - ($weight * $bars)) / ($bars - 1);
|
95 |
|
96 | @if unit($spacing) == 'px' {
|
97 | $spacing: floor($spacing);
|
98 | }
|
99 |
|
100 | @for $i from 2 through $bars {
|
101 | $offset: ($weight + $spacing) * ($i - 1);
|
102 | $shadow: append($shadow, 0 $offset 0 $color, comma);
|
103 | }
|
104 |
|
105 | // Icon container
|
106 | position: relative;
|
107 | display: inline-block;
|
108 | vertical-align: middle;
|
109 | width: $width;
|
110 | height: $height;
|
111 | cursor: pointer;
|
112 |
|
113 | // Icon bars
|
114 | &::after {
|
115 | position: absolute;
|
116 | top: 0;
|
117 | left: 0;
|
118 |
|
119 | display: block;
|
120 | width: 100%;
|
121 | height: $weight;
|
122 |
|
123 | background: $color;
|
124 | box-shadow: $shadow;
|
125 |
|
126 | content: '';
|
127 | }
|
128 |
|
129 | // Hover state
|
130 | @if $color-hover {
|
131 | // Generate CSS
|
132 | @for $i from 2 through $bars {
|
133 | $offset: ($weight + $spacing) * ($i - 1);
|
134 | $hover-shadow: append($hover-shadow, 0 $offset 0 $color-hover, comma);
|
135 | }
|
136 |
|
137 | &:hover::after {
|
138 | background: $color-hover;
|
139 | box-shadow: $hover-shadow;
|
140 | }
|
141 | }
|
142 | }
|
143 |
|
144 | /// Adds a downward-facing triangle as a background image to an element. The image is formatted as an SVG, making it easy to change the color. Because Internet Explorer doesn't support encoded SVGs as background images, a PNG fallback is also included.
|
145 | /// There are two PNG fallbacks: a black triangle and a white triangle. The one used depends on the lightness of the input color.
|
146 | ///
|
147 | /// @param {Color} $color [$black] - Color to use for the triangle.
|
148 | @mixin background-triangle($color: $black) {
|
149 | $rgb: 'rgb%28#{round(red($color))}, #{round(green($color))}, #{round(blue($color))}%29';
|
150 |
|
151 | background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='32' height='24' viewBox='0 0 32 24'><polygon points='0,0 32,0 16,24' style='fill: #{$rgb}'></polygon></svg>");
|
152 |
|
153 | @media screen and (min-width:0\0) {
|
154 | @if lightness($color) < 60% {
|
155 | // White triangle
|
156 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIpJREFUeNrEkckNgDAMBBfRkEt0ObRBBdsGXUDgmQfK4XhH2m8czQAAy27R3tsw4Qfe2x8uOO6oYLb6GlOor3GF+swURAOmUJ+RwtEJs9WvTGEYxBXqI1MQAZhCfUQKRzDMVj+TwrAIV6jvSUEkYAr1LSkcyTBb/V+KYfX7xAeusq3sLDtGH3kEGACPWIflNZfhRQAAAABJRU5ErkJggg==');
|
157 | }
|
158 | @else {
|
159 | // Black triangle
|
160 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMBJREFUeNrEllsOhCAMRVszC9IlzU7KCmVHTJsoMWYMUtpyv9BgbuXQB5ZSdgBYYY4ycgBivk8KYFsQMfMiTTBP4o3nUzCKzOabLJbLy2/g31evGkAginR4/ZegKH5qX3bJCscA3t0x3kgO5tQFyhhFf50xRqFLbyMUNJQzgyjGS/wgCpvKqkRBpuWrE4V9d+1E4dPUXqIg107SQOE/2DRQxMwTDygIInVDET9T3lCoj/6j/VCmGjZOl2lKpZ8AAwDQP7zIimDGFQAAAABJRU5ErkJggg==');
|
161 | }
|
162 | }
|
163 | }
|
164 |
|
165 | /// Applies the micro clearfix hack popularized by Nicolas Gallagher. Include this mixin on a container if its children are all floated, to give the container a proper height.
|
166 | /// The clearfix is augmented with specific styles to prevent borders in flexbox environments
|
167 | /// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix Hack
|
168 | /// @link http://danisadesigner.com/blog/flexbox-clear-fix-pseudo-elements/ Flexbox fix
|
169 | @mixin clearfix {
|
170 | &::before,
|
171 | &::after {
|
172 | display: table;
|
173 | content: ' ';
|
174 |
|
175 | @if $global-flexbox {
|
176 | flex-basis: 0;
|
177 | order: 1;
|
178 | }
|
179 | }
|
180 |
|
181 | &::after {
|
182 | clear: both;
|
183 | }
|
184 | }
|
185 |
|
186 | /// Adds CSS for a "quantity query" selector that automatically sizes elements based on how many there are inside a container.
|
187 | /// @link http://alistapart.com/article/quantity-queries-for-css Quantity Queries for CSS
|
188 | ///
|
189 | /// @param {Number} $max - Maximum number of items to detect. The higher this number is, the more CSS that's required to cover each number of items.
|
190 | /// @param {Keyword} $elem [li] - Tag to use for sibling selectors.
|
191 | @mixin auto-width($max, $elem: li) {
|
192 | @for $i from 2 through $max {
|
193 | &:nth-last-child(#{$i}):first-child,
|
194 | &:nth-last-child(#{$i}):first-child ~ #{$elem} {
|
195 | width: percentage(1 / $i);
|
196 | }
|
197 | }
|
198 | }
|
199 |
|
200 | /// Removes the focus ring around an element when a mouse input is detected.
|
201 | @mixin disable-mouse-outline {
|
202 | [data-whatinput='mouse'] & {
|
203 | outline: 0;
|
204 | }
|
205 | }
|
206 |
|
207 | /// Makes an element visually hidden, but still accessible to keyboards and assistive devices.
|
208 | /// @link http://snook.ca/archives/html_and_css/hiding-content-for-accessibility Hiding Content for Accessibility
|
209 | /// @link http://hugogiraudel.com/2016/10/13/css-hide-and-seek/
|
210 | @mixin element-invisible {
|
211 | position: absolute ;
|
212 | width: 1px;
|
213 | height: 1px;
|
214 | padding: 0;
|
215 | overflow: hidden;
|
216 | clip: rect(0,0,0,0);
|
217 | white-space: nowrap;
|
218 | clip-path: inset(50%);
|
219 | border: 0;
|
220 | }
|
221 |
|
222 | /// Reverses the CSS output created by the `element-invisible()` mixin.
|
223 | @mixin element-invisible-off {
|
224 | position: static ;
|
225 | width: auto;
|
226 | height: auto;
|
227 | overflow: visible;
|
228 | clip: auto;
|
229 | white-space: normal;
|
230 | clip-path: none;
|
231 | }
|
232 |
|
233 | /// Vertically centers the element inside of its first non-static parent,
|
234 | /// @link http://www.sitepoint.com/centering-with-sass/ Centering With Sass
|
235 | @mixin vertical-center {
|
236 | position: absolute;
|
237 | top: 50%;
|
238 | transform: translateY(-50%);
|
239 | }
|
240 |
|
241 | /// Horizontally centers the element inside of its first non-static parent,
|
242 | /// @link http://www.sitepoint.com/centering-with-sass/ Centering With Sass
|
243 | @mixin horizontal-center {
|
244 | position: absolute;
|
245 | left: 50%;
|
246 | transform: translateX(-50%);
|
247 | }
|
248 |
|
249 | /// Absolutely centers the element inside of its first non-static parent,
|
250 | /// @link http://www.sitepoint.com/centering-with-sass/ Centering With Sass
|
251 | @mixin absolute-center {
|
252 | position: absolute;
|
253 | top: 50%;
|
254 | left: 50%;
|
255 | transform: translate(-50%, -50%);
|
256 | }
|
257 |
|
258 | /// Iterates through breakpoints defined in `$breakpoint-classes` and prints the CSS inside the mixin at each breakpoint's media query. Use this with the grid, or any other component that has responsive classes.
|
259 | ///
|
260 | /// @param {Boolean} $small [true] - If `false`, the mixin will skip the `small` breakpoint. Use this with components that don't prefix classes with `small-`, only `medium-` and up.
|
261 | /// @param {Boolean} $auto-insert-breakpoints [true] - If `false`, the mixin will iterate over breakpoints without doing the media query itself. Useful for more complex media query generation as in the margin grid.
|
262 | @mixin -zf-each-breakpoint($small: true, $auto-insert-breakpoints: true) {
|
263 | $list: $breakpoint-classes;
|
264 |
|
265 | @if not $small {
|
266 | $list: sl-remove($list, $-zf-zero-breakpoint);
|
267 | }
|
268 |
|
269 | @each $name in $list {
|
270 | $-zf-size: $name !global;
|
271 |
|
272 | @if $auto-insert-breakpoints {
|
273 | @include breakpoint($name) {
|
274 | @content;
|
275 | }
|
276 | }
|
277 | @else {
|
278 | @content;
|
279 | }
|
280 | }
|
281 | }
|
282 |
|
283 | /// Generate the `@content` passed to the mixin with a value `$-zf-bp-value` related to a breakpoint, depending on the `$name` parameter:
|
284 | /// - For a single value, `$-zf-bp-value` is this value.
|
285 | /// - For a breakpoint name, `$-zf-bp-value` is the corresponding breakpoint value in `$map`.
|
286 | /// - For "auto", `$-zf-bp-value` is the corresponding breakpoint value in `$map` and is passed to `@content`, which is made responsive for each breakpoint of `$map`.
|
287 | /// @param {Number|Array|Keyword} $name [auto] - Single value, breakpoint name, or list of breakpoint names to use. "auto" by default.
|
288 | /// @param {Number|Map} $map - Map of breakpoints and values or single value to use.
|
289 | @mixin -zf-breakpoint-value(
|
290 | $name: auto,
|
291 | $map: null
|
292 | ) {
|
293 | @if $name == auto and type-of($map) == 'map' {
|
294 | // "auto"
|
295 | @each $k, $v in $map {
|
296 | @include breakpoint($k) {
|
297 | @include -zf-breakpoint-value($v, $map) {
|
298 | @content;
|
299 | }
|
300 | }
|
301 | }
|
302 | }
|
303 | @else {
|
304 | // breakpoint name
|
305 | @if type-of($name) == 'string' {
|
306 | $name: -zf-get-bp-val($map, $name);
|
307 | }
|
308 |
|
309 | // breakpoint value
|
310 | $-zf-bp-value: $name !global;
|
311 | @content;
|
312 | }
|
313 | }
|