_utils.sass 13.44 KiB
@function pxToRem($size)
$remSize: $size / 16
@return #{$remSize}rem
@function px2rem($size)
@return pxToRem($size)
$space-unit: 4 !default
@function space($spaces: 1)
@return #{$spaces * $space-unit / 16}rem
@mixin in-page-with-sidebar
@include media-breakpoint-up(desktop)
body:not(.full-width) &
@content
@mixin in-page-without-sidebar
@include media-breakpoint-up(desktop)
main > .blocks &,
body.full-width &,
@content
// Use this mixin to override with-aside or without-aside rules
@mixin in-page-with-or-without-sidebar
@include media-breakpoint-up(desktop)
body:not(.full-width) &,
main > .blocks &,
body.full-width &,
@content
// Aliases
@mixin full-page
@include in-page-without-sidebar
@content
@mixin not-full-page
@include in-page-with-sidebar
@content
@mixin in-page-program
.programs__section &
@content
@function half($size)
@return calc(#{$size} / 2)
@mixin link($color: $link-color, $unhover_decorated: true)
color: $color
text-decoration-line: underline
text-decoration-thickness: $link-underline-thickness
text-underline-offset: $link-underline-offset
transition: $link-transition
@if $unhover_decorated
text-decoration-color: rgba($color, $link-unhover-decoration-color-alpha)
@else
text-decoration-color: transparent
&:hover
text-decoration-color: rgba($color, 1)
text-decoration-thickness: 1px
@mixin link-hovered-underline-only
&:not(:hover)
text-decoration: transparent
@mixin hover-translate-icon($pseudo: after, $distance: 10)
&::#{$pseudo}
display: inline-block
transition: transform 0.55s $arrow-ease-transition
transform: translateX(0)
&:hover
&::#{$pseudo}
transform: translateX(#{px2rem($distance)})
@mixin sticky($offset-y: 0)
position: sticky
top: $offset-y
@if $header-sticky-enabled
transition: top $header-sticky-transition
html:not(.is-scrolling-down) &
top: calc(var(--header-height) + #{$offset-y})
// NEW UTILS
@mixin icon($icon-name: '', $pseudo-element: before, $non-breaking: false)
&::#{$pseudo-element}
content: map-get($icons, $icon-name)
display: inline-block
font-family: 'Icon'
font-style: normal
font-variant: normal
font-weight: normal
line-height: 1
speak: never
text-transform: none
vertical-align: middle
@if $non-breaking
content: " #{map-get($icons, $icon-name)}"
display: inline
@content // TODO : important de documenter ça
@mixin icon-block($icon-name: '', $pseudo-element: before, $non-breaking: false)
@include icon($icon-name, $pseudo-element, $non-breaking)
font-size: 44px
display: inline
@content
@mixin container
margin-left: auto
margin-right: auto
max-width: $grid-max-width
padding-left: half($grid-gutter-sm)
padding-right: half($grid-gutter-sm)
width: 100%
@include media-breakpoint-up(desktop)
padding-left: $grid-gutter
padding-right: $grid-gutter
@mixin grid($cols: 12, $breakpoint: false, $gap-y: $grid-gutter, $gap-x: $grid-gutter)
word-break: break-word
@if $breakpoint
@include media-breakpoint-up($breakpoint)
display: grid
grid-gap: $gap-y $gap-x
grid-template-columns: repeat($cols, 1fr)
@else
display: grid
grid-gap: $gap-y $gap-x
grid-template-columns: repeat($cols, 1fr)
@include media-breakpoint-down(desktop)
grid-gap: $grid-gutter-sm
// This must be used for content inside columns
@function col($quantity, $base: 12)
$quantity-on-base: $quantity / $base * 12
$width: calc( (100% + #{$grid-gutter}) / 12 * #{$quantity-on-base} - #{$grid-gutter} )
@return #{$width}
// This must be used for offset, outside columns
@function offset($quantity, $base: 12)
$quantity-on-base: $quantity / $base * 12
$width: calc( (100% + #{$grid-gutter}) / 12 * #{$quantity-on-base} )
@return #{$width}
// This must be used for offset, inside columns
@function col-offset($quantity, $base: 12)
$quantity-on-base: $quantity / $base * 12
$width: calc( (100% + #{$grid-gutter}) / 12 * #{$quantity-on-base} + #{$grid-gutter})
@return #{$width}
@function col-outside-container($quantity, $base: 12)
$responsive-grid-width: Min(100vw, (#{$grid-max-width}))
@return calc((#{$responsive-grid-width} + #{$grid-gutter} * 2) / #{$base} * #{$quantity} - #{$grid-gutter} * 2)
@function container-margin-x
@return Max(#{$grid-gutter}, calc(50vw - #{$grid-max-width} / 2 + #{$grid-gutter}))
@mixin container-margin-left
margin-left: container-margin-x()
@mixin container-margin-right
margin-right: container-margin-x()
@mixin stretched-link($pseudo-element: after)
&::#{$pseudo-element}
bottom: 0
content: ''
left: 0
position: absolute
right: 0
top: 0
z-index: $zindex-stretched-link
@mixin aspect-ratio($ratio, $selector: 'iframe', $background: false)
@if $background
aspect-ratio: #{$ratio}
background: $background
#{$selector}
aspect-ratio: #{$ratio}
display: block
width: 100%
@mixin handle-svg-fit
picture.is-svg
img
object-fit: contain
@mixin article($background: null)
position: relative
display: flex
flex-direction: column
.media
@include handle-svg-fit
margin-bottom: $spacing1
order: -1
overflow: hidden
img
display: block
object-fit: cover
@if $article-media-aspect-ratio
aspect-ratio: $article-media-aspect-ratio
h2, h3, [itemprop=headline]
@include h3
a
display: block
@include stretched-link
text-decoration: none
p + time
margin-top: $spacing0
time
@include meta
color: $color-text-alt
display: block
@mixin post-time-author-flex
.post-meta
display: flex
flex-wrap: wrap
.post-author p::before
content: ' • '
@mixin list-section
@include list-reset
> li
border-bottom: 1px solid $color-border
padding-bottom: $spacing1
padding-top: $spacing1
position: relative
> .title
@include h2
transition: color 0.55s
@include media-breakpoint-down(desktop)
@include icon(arrow-right, after, true)
bottom: $spacing0
position: absolute
right: 0
@include media-breakpoint-up(desktop)
@include arrow-right-hover
display: block
&::after
transform: translateX(0)
position: relative
&:hover
&::after
transform: translateX($spacing0)
a
text-decoration: none
&:hover
color: $color-accent
@include media-breakpoint-down(desktop)
a:nth-child(2)
margin-top: calc(#{$spacing0} / 2)
a, p
display: block
@include media-breakpoint-up(desktop)
align-items: baseline
display: flex
justify-content: space-between
@mixin visually-hidden
clip: rect(0,0,0,0) !important
border: 0 !important
height: 1px !important
margin: -1px !important
overflow: hidden !important
padding: 0 !important
position: absolute !important
white-space: nowrap !important
width: 1px !important
@mixin button-reset
appearance: none
background: transparent
border: none
border-radius: 0
cursor: pointer
user-select: none
&:active,
&:focus
box-shadow: inset 0 0 0 0.25rem rgba($color-text, 0.25)
// TODO : vérifier si l'outline 0 est vraiment nécessaire
// outline: 0
@mixin list-reset
list-style: none
padding-left: 0
margin-bottom: 0
margin-top: 0
@mixin inset($top: 0, $right: $top, $bottom: $top, $left: $top)
inset: $top $right $bottom $left
// polyfill for inset
@supports not (inset: $top)
bottom: $bottom
left: $left
right: $right
top: $top
@function color-contrast($color, $amount)
@if lightness($color) > 50%
$amount: $amount * -1
@return scale-color($color, $lightness: $amount)
@mixin button-icon($icon: false)
@include button-reset
line-height: $body-line-height
border: 1px solid $hero-color
padding: half($spacing0) $spacing1
white-space: nowrap
@if $icon
@include icon-block($icon, after)
@mixin text-underline
text-decoration-color: $color-border
text-decoration-line: underline
text-decoration-thickness: 1px
text-underline-offset: 3px
text-decoration-line: underline
@mixin arrow-right-hover
position: relative
display: flex
justify-content: space-between
align-items: center
@include icon(arrow, after)
opacity: 0
transform: translateX(-20px)
transition: 0.55s $arrow-ease-transition
position: absolute
right: 0
&:hover
&:after
opacity: 1
transform: translateX(0)
@mixin top-flex
@include in-page-without-sidebar
align-items: baseline
display: flex
.block-title
width: col(4)
&:not(.hidden) + .description
margin-left: $grid-gutter
.description
margin-top: 0
width: col(8)
@mixin collapsed-figcaption
figcaption
@include meta
color: $color-text-alt
position: absolute
display: block
left: 0
right: 0
text-align: right
z-index: 10
&::before
@include meta
content: '©'
position: absolute
right: 0
top: 0
background: $hero-background-color
text-align: center
padding: half($spacing0)
display: block
.credit-content
@include meta
background: $hero-background-color
display: none
padding: half($spacing0)
padding-right: $spacing1
a
color: inherit
text-decoration-color: inherit
&:focus
.credit-content
display: block
@include media-breakpoint-up(desktop)
&:before
padding-right: 0
@include media-breakpoint-down(desktop)
position: relative
background: $color-background
&::before
background: transparent
.credit-content
display: block
background: transparent
position: relative
&:hover
figcaption .credit-content
display: block
@mixin dropdown-i18n
position: relative
.dropdown-menu
margin-top: $header-nav-padding-y
padding-left: $spacing1
padding-bottom: $spacing0
padding-top: $spacing0
padding-right: $spacing1
right: 0
li a
padding-bottom: half($spacing0)
padding-top: half($spacing0)
display: block
&.is-checked
display: flex
justify-content: space-between
align-items: center
gap: $spacing2
text-decoration: none !important
@include icon(caret, after)
transform: rotate(-14deg) skewX(-30deg)
// https://gist.github.com/jonathantneal/d0460e5c2d5d7f9bc5e6
@function str-replace($string, $search, $replace: "")
$index: str-index($string, $search)
@if $index
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
@return $string
@mixin font-face($name, $path, $weight: 400, $style: normal, $exts: (eot woff2 woff ttf svg))
$src: null
$extmods: (eot:"?", svg:"#" + str-replace($name," ","_"))
$formats: (otf: "opentype", ttf: "truetype")
@each $ext in $exts
$extmod: if(map-has-key($extmods, $ext), $ext + map-get($extmods, $ext), $ext)
$format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext)
$src: append($src, url(quote("/assets/fonts/" + $path + "." + $extmod)) format(quote($format)), comma,)
@font-face
font-family: quote($name)
font-style: $style
font-weight: $weight
font-display: swap
src: $src
@mixin sidebar($side: start)
@include media-breakpoint-down(desktop)
padding: 0 half($grid-gutter-sm)
margin-bottom: $spacing3
@include media-breakpoint-up(desktop)
@if $side == start
@include container-margin-left
left: 0
@else
@include container-margin-right
right: 0
margin-top: 0
top: 0
height: 100%
position: absolute
width: col-outside-container(4)
& > div
@include sticky($spacing1)
.toc-container
border-top: 1px solid $color-border
padding-top: $spacing1
position: static
margin-left: 0
// Old browsers support
@mixin browser-under-safari-16
@media not all and (min-resolution:.001dpcm)
@supports (-webkit-appearance:none) and (display:flow-root)
@content