Source: breakpoints.scss

  1. /**
  2. * @namespace Breakpoints
  3. */
  4. @use 'sass:meta';
  5. @use 'sass:list';
  6. @use 'sass:map';
  7. @use 'globals' as *;
  8. @use 'util';
  9. $jig---auto-breakpoint: list.nth(map.keys($jig---breakpoint-config), 1);
  10. /**
  11. * @namespace Breakpoints:get-auto-breakpoint
  12. */
  13. /**
  14. * Returns the current auto breakpoint value.
  15. *
  16. * @memberof Breakpoints:get-auto-breakpoint
  17. * @function
  18. * @name get-auto-breakpoint
  19. * @alias get-auto-breakpoint
  20. *
  21. * @returns {String} the name of the current named auto breakpoint
  22. *
  23. * @see set-auto-breakpoint
  24. * @see reset-auto-breakpoint
  25. *
  26. * @example
  27. * get-auto-breakpoint()
  28. * => 'medium'
  29. */
  30. @function get-auto-breakpoint(){
  31. @return $jig---auto-breakpoint;
  32. }
  33. /**
  34. * @namespace Breakpoints:set-auto-breakpoint
  35. */
  36. /**
  37. * Sets the auto breakpoint to a named breakpoint value.
  38. * Hint: in Sass we do _not_ have to do this manually, if we want to use auto breakpoint values,
  39. * since blocks are always evaluated _after_ the block mixin around the block, which results
  40. * in the block knowing the breakpoint value automatically from the mixin around it.
  41. *
  42. * @memberof Breakpoints:set-auto-breakpoint
  43. * @function
  44. * @name set-auto-breakpoint
  45. * @alias set-auto-breakpoint
  46. *
  47. * @param {String} $breakpoint - a named breakpoint defined in the jig config
  48. * @throws error if breakpoint is unknown
  49. *
  50. * @see reset-auto-breakpoint
  51. * @example
  52. * \@include set-auto-breakpoint(medium);
  53. * \@include breakpoint(medium){
  54. * ...
  55. * }
  56. */
  57. @mixin set-auto-breakpoint($breakpoint){
  58. @if map.has-key($jig---breakpoint-config, $breakpoint) {
  59. $jig---auto-breakpoint: $breakpoint !global;
  60. } @else {
  61. @error 'jig:set-current-breakpoint | unknown named breakpoint "#{$breakpoint}"';
  62. }
  63. }
  64. /**
  65. * @namespace Breakpoints:reset-auto-breakpoint
  66. */
  67. /**
  68. * Resets the auto breakpoint to the first/smallest named breakpoint defined in the jig config.
  69. * Hint: this is automatically called at the end of the breakpoint mixin, so usually you should be fine
  70. * never calling this manually
  71. *
  72. * @memberof Breakpoints:reset-auto-breakpoint
  73. * @function
  74. * @name reset-auto-breakpoint
  75. * @alias reset-auto-breakpoint
  76. *
  77. * @see set-auto-breakpoint
  78. * @example
  79. * \@include reset-auto-breakpoint();
  80. */
  81. @mixin reset-auto-breakpoint(){
  82. $jig---auto-breakpoint: list.nth(map.keys($jig---breakpoint-config), 1) !global;
  83. }
  84. /**
  85. * @namespace Breakpoints:is-named-breakpoint
  86. */
  87. /**
  88. * Returns if the given breakpoint is a registered named breakpoint to be found in the jig config.
  89. *
  90. * @memberof Breakpoints:is-named-breakpoint
  91. * @function
  92. * @name is-named-breakpoint
  93. * @alias is-named-breakpoint
  94. *
  95. * @param {String} $breakpoint - a named breakpoint defined in the jig config
  96. * @returns {Boolean} true if breakpoint is a registered named breakpoint name
  97. *
  98. * @example
  99. * is-named-breakpoint(medium)
  100. * => true
  101. */
  102. @function is-named-breakpoint($breakpoint){
  103. @return map.has-key($jig---breakpoint-config, $breakpoint);
  104. }
  105. /**
  106. * @namespace Breakpoints:build-breakpoint-range
  107. */
  108. /**
  109. * Returns a string to be used in a media query, which defines the range/bounds of a breakpoint with
  110. * min and/or max value.
  111. *
  112. * @memberof Breakpoints:build-breakpoint-range
  113. * @function
  114. * @name build-breakpoint-range
  115. * @alias build-breakpoint-range
  116. *
  117. * @param {?Number} [$min=null] - the min width of the breakpoint
  118. * @param {?Number} [$max=null] - the max width of the breakpoint
  119. * @returns {String} the media query string for the breakpoint range
  120. *
  121. * @example
  122. * build-breakpoint-range(0, 767px)
  123. * => '(min-width: 0) and (max-width: 767px)'
  124. * build-breakpoint-range(null, 100rem)
  125. * => '(max-width: 100rem)'
  126. */
  127. @function build-breakpoint-range($min:null, $max:null){
  128. @return util.str-join(
  129. [
  130. if($min != null, '(min-width: #{$min})', null),
  131. if($max != null, '(max-width: #{$max})', null)
  132. ],
  133. ' and '
  134. );
  135. }
  136. /**
  137. * @namespace Breakpoints:build-breakpoint-query
  138. */
  139. /**
  140. * Constructs a query to be used in a media query, based on a breakpoint definition.
  141. * Also automatically converts values to rem.
  142. *
  143. * Directions in composite definitions may be "up", "down" or "only".
  144. *
  145. * You may also define the special breakpoints "landscape" or "portrait" to cover device orientations.
  146. *
  147. * @memberof Breakpoints:build-breakpoint-query
  148. * @function
  149. * @name build-breakpoint-query
  150. * @alias build-breakpoint-query
  151. *
  152. * @param {?Number|Literal|List<String>} [$breakpoint-definition=0] - either a simple number or a composite definition of width and direction, where the width may either be a number or a name defined in the named breakpoints
  153. * @returns {String} the media query string for the breakpoint definition
  154. * @throws error if named breakpoint is unknown
  155. * @throws error if an unnamed breakpoint has an "only" direction
  156. *
  157. * @example
  158. * build-breakpoint-query(200rem)
  159. * => '(min-width: 200rem)'
  160. * build-breakpoint-query(small down)
  161. * => '(max-width: 199rem)'
  162. * build-breakpoint-query(('large' 'only'))
  163. * => '(min-width: 200rem) and (max-width: 499rem)'
  164. * build-breakpoint-query(1024px only)
  165. * => '(min-width: 64rem) and (max-width: 64rem)'
  166. * build-breakpoint-query(landscape)
  167. * => '(orientation: landscape)'
  168. */
  169. @function build-breakpoint-query($breakpoint-definition:0){
  170. $breakpoint: if($breakpoint-definition and (list.length($breakpoint-definition) > 0), list.nth($breakpoint-definition, 1), 0);
  171. $direction: if($breakpoint-definition and (list.length($breakpoint-definition) > 1), list.nth($breakpoint-definition, 2), 'up');
  172. $breakpoint-name: null;
  173. $next-breakpoint: null;
  174. $min: null;
  175. $max: null;
  176. $query-em-conversion-base: 16px; // this is always 16px, no matter what is defined on <html>
  177. @if $breakpoint == 'overwrite' {
  178. @return '(min-width: 0)';
  179. } @else if ($breakpoint == 'landscape') or ($breakpoint == 'portrait') {
  180. @return '(orientation: #{$breakpoint})';
  181. } @else if meta.type-of($breakpoint) == 'string' {
  182. @if is-named-breakpoint($breakpoint) {
  183. $breakpoint-name: $breakpoint;
  184. $breakpoint: map.get($jig---breakpoint-config, $breakpoint-name);
  185. $next-breakpoint: util.map-next($jig---breakpoint-config, $breakpoint-name);
  186. } @else {
  187. @error 'jig:build-breakpoint-query | "#{$breakpoint-definition}" is not a defined breakpoint';
  188. }
  189. }
  190. @if ($breakpoint-name == null) and ($direction == 'only') {
  191. @error 'jig:build-breakpoint-query | only named media queries can have an "only" range';
  192. }
  193. // we are building media queries with em instead of rem and px
  194. // why? => https://zellwk.com/blog/media-query-units/
  195. @if ($direction == 'only') or ($direction == 'up') {
  196. $min: util.to-em($breakpoint, $query-em-conversion-base);
  197. }
  198. @if ($direction == 'only') or ($direction == 'down') {
  199. @if $breakpoint-name == null {
  200. $max: util.to-em($breakpoint, $query-em-conversion-base);
  201. } @else if $next-breakpoint != null {
  202. $max: util.to-em($next-breakpoint, $query-em-conversion-base) - util.to-em(1px, $query-em-conversion-base);
  203. }
  204. }
  205. @if ($min == 0) and ($max == null){
  206. $min: null;
  207. }
  208. @return build-breakpoint-range($min, $max);
  209. }
  210. /**
  211. * @namespace Breakpoints:breakpoint
  212. */
  213. /**
  214. * Renders media queries based one one or more breakpoint definitions.
  215. *
  216. * @memberof Breakpoints:breakpoint
  217. * @function
  218. * @name breakpoint
  219. * @alias breakpoint
  220. *
  221. * @param {Number|Literal|List<String>|List<Literal>|List<List<String>>} $breakpoint-definitions - a list of breakpoint definitions according to build-breakpoint-query
  222. *
  223. * @example
  224. * \@include breakpoint(small){
  225. * ...
  226. * }
  227. * \@include breakpoint(small down, large up){
  228. * ...
  229. * }
  230. */
  231. @mixin breakpoint($breakpoint-definitions...){
  232. @each $breakpoint-definition in $breakpoint-definitions {
  233. $query: build-breakpoint-query($breakpoint-definition);
  234. $breakpoint: if(list.length($breakpoint-definition) > 0, list.nth($breakpoint-definition, 1), 0);
  235. $direction: if(list.length($breakpoint-definition) > 1, list.nth($breakpoint-definition, 2), 'up');
  236. $breakpoint-index: index(map.keys($jig---breakpoint-config), list.nth($breakpoint-definition, 1));
  237. $print-breakpoint-index: list.index(map.keys($jig---breakpoint-config), $jig---print-breakpoint);
  238. // set current breakpoint var to mixin breakpoint value to allow for auto-evaluation inside
  239. @if is-named-breakpoint($breakpoint){
  240. @include set-auto-breakpoint($breakpoint);
  241. }
  242. @if $query == '' {
  243. @content;
  244. } @else {
  245. @if(
  246. ($breakpoint-index != null)
  247. and (
  248. ($breakpoint-index <= $print-breakpoint-index)
  249. or ($direction == 'down')
  250. )
  251. ){
  252. @media print, screen and #{$query} {
  253. @content;
  254. }
  255. } @else {
  256. @media screen and #{$query} {
  257. @content;
  258. }
  259. }
  260. }
  261. // restore initial value after mixin has been rendered
  262. @include reset-auto-breakpoint();
  263. }
  264. }
  265. /**
  266. * @namespace Breakpoints:breakpoint-value
  267. */
  268. /**
  269. * Search for a value, defined for a breakpoint, in a given map of values.
  270. * The function escalates in a mobile-first manner. So we take the value for the smallest breakpoint
  271. * and step up the breakpoints one by one until we reach the defined breakpoint. So, if we want the
  272. * according value for "large", but we only have a value for "medium", we'll get the "medium" value, which,
  273. * in mobile-first manner, escalates upwards and is the "large" value if nothing else is defined.
  274. *
  275. * @memberof Breakpoints:breakpoint-value
  276. * @function
  277. * @name breakpoint-value
  278. * @alias breakpoint-value
  279. *
  280. * @param {*|Map} $value - a map of breakpoint-keyed map of values, or a simple value
  281. * @param {Literal|String} $breakpoint - either "auto" (to use the current breakpoint) or one of the defined named breakpoints
  282. * @returns {*|null} the breakpoint value or null if nothing was found
  283. * @throws error if named breakpoint is unknown
  284. *
  285. * @example
  286. * breakpoint-value(
  287. * (
  288. * 'small' : 10px,
  289. * 'medium' : 20px
  290. * ),
  291. * large
  292. * )
  293. * => 20px
  294. */
  295. @function breakpoint-value($value, $breakpoint:'auto'){
  296. @if ($breakpoint != 'auto') and not map.has-key($jig---breakpoint-config, $breakpoint) {
  297. @error 'jig:breakpoint-value | given breakpoint "#{$breakpoint}" not defined';
  298. }
  299. @if meta.type-of($value) == 'map' {
  300. $res: null;
  301. @if $breakpoint == 'auto' {
  302. $breakpoint: get-auto-breakpoint();
  303. }
  304. @each $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config {
  305. $breakpoint-value: map.get($value, $breakpoint-name);
  306. @if $breakpoint-value != null {
  307. $res: $breakpoint-value;
  308. }
  309. @if $breakpoint-name == $breakpoint {
  310. @return $res;
  311. }
  312. }
  313. @return null;
  314. } @else {
  315. @return $value;
  316. }
  317. }
  318. /**
  319. * @namespace Breakpoints:attributes-for-breakpoints
  320. */
  321. /**
  322. * Renders attribute values for given attributes for defined breakpoints.
  323. *
  324. * Definitions will be rendered together if possible, minimizing the amount of media queries.
  325. * However, each call of this mixin will, most likely, render multiple media queries, so keep a close eye
  326. * on your media query structure to avoid unnecessarily doubled definitions and keep media queries to a minimum.
  327. * If in doubt, it might be a better idea to write the queries manually, perhaps rather using `map.get` or
  328. * `breakpoint-value` to automatically pull values from breakpoint value maps.
  329. *
  330. * @memberof Breakpoints:attributes-for-breakpoints
  331. * @function
  332. * @name attributes-for-breakpoints
  333. * @alias attributes-for-breakpoints
  334. *
  335. * @see attribute-for-breakpoints
  336. *
  337. * @param {Map} $attributes - keys are attribute names, while values are either plain values or maps with breakpoint name keys, providing different values per breakpoint
  338. * @param {Number} [$factor=null] - if a float factor is provided all values will be multiplied with this factor
  339. *
  340. * @example
  341. * \@include attributes-for-breakpoints(
  342. * (
  343. * 'font-size' : 12px,
  344. * 'line-height' : (
  345. * 'small' : 1,
  346. * 'large' : 1.25
  347. * ),
  348. * 'margin-top' : (
  349. * 'small' : 10px,
  350. * 'medium' : 20px
  351. * )
  352. * ),
  353. * 2.0
  354. * );
  355. */
  356. @mixin attributes-for-breakpoints($attributes, $factor:null){
  357. $attributes-for-breakpoints: ();
  358. @each $attribute-name, $attribute-value in $attributes {
  359. @if meta.type-of($attribute-value) != 'map' {
  360. @if $factor == null {
  361. #{$attribute-name}: $attribute-value;
  362. } @else {
  363. #{$attribute-name}: ($factor * $attribute-value);
  364. }
  365. } @else {
  366. @each $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config {
  367. $breakpoint-value: map.get($attribute-value, $breakpoint-name);
  368. @if $breakpoint-value != null {
  369. $breakpoint-attributes: map.get($attributes-for-breakpoints, $breakpoint-name);
  370. @if $breakpoint-attributes == null {
  371. $breakpoint-attributes: ();
  372. }
  373. $breakpoint-attributes: map.merge(
  374. $breakpoint-attributes,
  375. ($attribute-name : $breakpoint-value)
  376. );
  377. $attributes-for-breakpoints: map.merge(
  378. $attributes-for-breakpoints,
  379. ($breakpoint-name : $breakpoint-attributes)
  380. );
  381. }
  382. }
  383. }
  384. }
  385. @each $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config {
  386. $breakpoint-attributes: map.get($attributes-for-breakpoints, $breakpoint-name);
  387. @if ($breakpoint-attributes != null) and (list.length(map.keys($breakpoint-attributes)) > 0) {
  388. @include breakpoint($breakpoint-name){
  389. @each $attribute-name, $attribute-value in $breakpoint-attributes {
  390. @if $factor == null {
  391. #{$attribute-name}: $attribute-value;
  392. } @else {
  393. #{$attribute-name}: ($factor * $attribute-value);
  394. }
  395. }
  396. }
  397. }
  398. }
  399. }
  400. /**
  401. * @namespace Breakpoints:attribute-for-breakpoints
  402. */
  403. /**
  404. * Renders attribute values for given attribute for defined breakpoints.
  405. *
  406. * This is the single attribute version of `attributes-for-breakpoints`.
  407. * Since this version does not optimize the usage of media queries, please make sure to only use this mixin,
  408. * if you'll definitely only have one attribute to be defined in multiple breakpoints.
  409. *
  410. * @memberof Breakpoints:attribute-for-breakpoints
  411. * @function
  412. * @name attribute-for-breakpoints
  413. * @alias attribute-for-breakpoints
  414. *
  415. * @see attributes-for-breakpoints
  416. *
  417. * @param {String} $attribute - the name of the attribute you want to set
  418. * @param {*} $value - the value to set the attribute to
  419. * @param {Number} [$factor=null] - if a float factor is provided the value will be multiplied with this factor
  420. *
  421. * @example
  422. * \@include attribute-for-breakpoints(
  423. * 'line-height',
  424. * (
  425. * 'small' : 1,
  426. * 'large' : 1.25
  427. * ),
  428. * 1.0
  429. * );
  430. */
  431. @mixin attribute-for-breakpoints($attribute, $value, $factor:null){
  432. $attributes: ();
  433. $attributes: map.merge($attributes, ('#{$attribute}' : $value));
  434. @include attributes-for-breakpoints($attributes, $factor);
  435. }
  436. /**
  437. * @namespace Breakpoints:overwrite-breakpoint-for-attributes
  438. */
  439. /**
  440. * Use this, if you need to overwrite attribute values previously defined in (a) breakpoint(s).
  441. *
  442. * A use case might be, for example, to set a font-size to a static value in an element with a responsive,
  443. * breakpoint-based font-size definition.
  444. *
  445. * @memberof Breakpoints:overwrite-breakpoint-for-attributes
  446. * @function
  447. * @name overwrite-breakpoint-for-attributes
  448. * @alias overwrite-breakpoint-for-attributes
  449. *
  450. * @param {Map} $attributes - keys are attribute names, while values are either plain values or maps with breakpoint name keys, providing different values per breakpoint
  451. * @param {Number} [$factor=null] - if a float factor is provided all values will be multiplied with this factor
  452. *
  453. * @see overwrite-breakpoint-for-attribute
  454. *
  455. * @example
  456. * \@include overwrite-breakpoint-for-attributes(
  457. * (
  458. * 'font-size' : 12px,
  459. * 'line-height' : 1.25
  460. * 'margin-top' : 20px
  461. * ),
  462. * 2.0
  463. * );
  464. */
  465. @mixin overwrite-breakpoint-for-attributes($attributes, $factor:null){
  466. @include breakpoint('overwrite'){
  467. @each $attribute-name, $attribute-value in $attributes {
  468. @if $factor == null {
  469. #{$attribute-name}: $attribute-value;
  470. } @else {
  471. #{$attribute-name}: ($factor * $attribute-value);
  472. }
  473. }
  474. }
  475. }
  476. /**
  477. * @namespace Breakpoints:overwrite-breakpoint-for-attribute
  478. */
  479. /**
  480. * Use this, if you need to overwrite an attribut value previously defined in (a) breakpoint(s).
  481. *
  482. * A use case might be, for example, to set a font-size to a static value in an element with a responsive,
  483. * breakpoint-based font-size definition.
  484. *
  485. * @memberof Breakpoints:overwrite-breakpoint-for-attribute
  486. * @function
  487. * @name overwrite-breakpoint-for-attribute
  488. * @alias overwrite-breakpoint-for-attribute
  489. *
  490. * @see overwrite-breakpoint-for-attributes
  491. *
  492. * @param {String} $attribute - the name of the attribute you want to set
  493. * @param {*} $value - the value to set the attribute to
  494. * @param {Number} [$factor=null] - if a float factor is provided the value will be multiplied with this factor
  495. *
  496. * @example
  497. * \@include overwrite-breakpoint-for-attribute(font-size, 12px, 2.0);
  498. */
  499. @mixin overwrite-breakpoint-for-attribute($attribute, $value, $factor:null){
  500. $attributes: ();
  501. $attributes: map.merge($attributes, ('#{$attribute}' : $value));
  502. @include overwrite-breakpoint-for-attributes($attributes, $factor);
  503. }
  504. /**
  505. * @namespace Breakpoints:overwrite-breakpoint
  506. */
  507. /**
  508. * Use this, if you need to overwrite something previously defined in (a) breakpoint(s).
  509. *
  510. * A use case might be, for example, to redefine something statically in an override situation, which has
  511. * been defined responsively before.
  512. *
  513. * @memberof Breakpoints:overwrite-breakpoint
  514. * @function
  515. * @name overwrite-breakpoint
  516. * @alias overwrite-breakpoint
  517. *
  518. * @example
  519. * \@include overwrite-breakpoint(){
  520. * font-size: 12xp;
  521. * margin-top: 20px;
  522. * }
  523. */
  524. @mixin overwrite-breakpoint(){
  525. @include breakpoint('overwrite'){
  526. @content;
  527. }
  528. }