Skip to content

Instantly share code, notes, and snippets.

@matthewjumpsoffbuildings
Last active September 29, 2021 12:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewjumpsoffbuildings/dbdc480fb3733188596c0018b24dd473 to your computer and use it in GitHub Desktop.
Save matthewjumpsoffbuildings/dbdc480fb3733188596c0018b24dd473 to your computer and use it in GitHub Desktop.
Headwind Readme

Headwind

Contents

Usage

Add your headwind declarations to any elements via the hw attribute

<div hw="headwind goes here">

The final output will be something like

<div class="headwind classes">

If the element already has a class attribute, the headwind classes will be appended to it, if not a class attribute will be added. If you are using Vue components, you can still use bound class/style properties, they will be ignored by headwind. In the following example headwind wont touch the :class and :style attributes, instead it will create a fresh static class attribute

<div hw="headwind goes here" :class="{ active: isActive }" :style="styleObject">

If you are using the loader with a pug file, use the (hw="") attribute, eg

h1.some-class( hw="this will be processed by headwind" )

If you want to spread your headwind definition over multiple lines, in Vue templates you should be ok to use hw="", but in pug you should use backticks `, eg

li(hw=`
  multiline
  classes
`)

Apply a single style

property:value

This is the same as inline styles, nothing amazing here. The property can be any valid CSS property eg font-size, background, and val can be any valid CSS property value eg 10em, 50%, 2.3, #FF0000, rgb(1,1,1) etc.

<p hw="color:white">

If your value has spaces, like an image path, you will need to wrap that part in a string literal ' ' eg

<div hw="background-image:url('some image with spaces.jpg')">

Shorthand property names

You can also choose to use abbreviated property names from the prebuilt list of abbreviations, or add/change the abbreviations in the headwind.js config. There are 2 sets of shorthand names, short and medium. For example the following properties all apply to font-size:

<a hw="fs:10px"> <!-- short -->
<a hw="f-size:10px"> <!-- medium -->
<a hw="font-size:10px">

Default units

Every relevant CSS property also comes with its own default value units. These can also be customised in the config if needed. For example for the width/w property, the default unit is % so the following values would be the same:

<span hw="w:100">
<span hw="width:100%">

Computed ratios

You can also use ratios, any value in the form integer/integer will return a percentage value. As with everything else, the output CSS will only contain the ratios you used, and none you didnt

<div hw="w:1/4"> 
<!-- same as --> 
<div hw="width:25%">

<h1 hw="h:12/5"> 
<!-- same as --> 
<h1 hw="height:240%">

<p hw="pb:3/7"> 
<!-- same as -->  
<p hw="padding-bottom:42.85714286%">

Global variables

Global variables defined in the config file can be inserted as values for any properties using the $ prefix

vars: {
  orange: '#ffa500'
}
<h1 hw="color:$orange">

You can also nest vars in the config file, in which case you can access them via dot notation

vars: {
  colors: {
    orange: '#ffa500'
  },
  sizes: {
    big: '100px'
  }
}
<h1 hw="font-size:$sizes.big, color:$colors.orange">

Single pseudo-class style

psuedo.property:value

If you want to add a single style to an element on hover, you can prefix the property:value pair with hover. - note the . separating the pseudo from the property:value

<a hw="hover.padding:20px">

You can still use shorthand property names, vars, default units, computed ratios etc

<a hw="hover.pb:1/4">
<a hw="hover.pt:$foo">
<a hw="hover.padding-top:100">

This works with any pseudo class

<button hw="disabled.opacity:0.5">
<a hw="active.color:green">
<input hw="checked.bg:blue">

Single pseudo-element style

psuedo.property:value

Same format as pseudo class styles. Note the string literal ' ' wrapping the content value, since it contains spaces

<i hw="after.content:'Hello there 😊'">

Multiple single styles and pseudos

When adding multiple rules you need to use , to separate them. Whitespace doesnt matter around the individual rules, eg you can have as much space as you want between the commas.

<a hw="bg:$red, hover.bg:$green, before.content:'🎉 + 🍷', after.content:'= 🤮'">

Single breakpoint style

Breakpoints will come with some sensible defaults, but can be overwritten or supplemented in the config. The default breakpoints in the config js have the @ prefix, but that can be changed if preferred

<h1 hw="@sm.font-size:2rem">

Digging deeper

So far this is all handy enough, being able to assign a single style 'inline' that will respond to media queries and hover/before/after etc is cool, but if you want to do multiple things in response to hover, or breakpoints, it would get tedious to write @md.font-size:3rem, @md.color:red, @md:width:50% (heres lookin at you tailwind)

So you can also group and nest breakpoint and pseudo rules.

Group of rules for a breakpoint

Note the js style object syntax mediaQuery:{ property:value }, everything inside the { } is only applied when the @md breakpoint is active. As with normal rules, you need to comma separate the nested rules. The following example is both the shorthand and long version of the same set of rules, all applied at the medium breakpoint

<div hw="@md:{ w:50, p:1, h:auto }">
<div hw="@md:{ width:50%, padding:1rem, height:auto }">

Group of rules for a pseudo class/element

Similarly you can group rules for pseudo selectors/elements

<i hw="before:{ bg:$red, content:'🗿', opacity:0.5 }">

2 or more groups of rules

When using multiple rule groups you just need to comma separate each rule set

<div hw="@md:{ w:50%, p:1, h:auto }, @lg:{ w:30%, p:2, h:100vh }">

Nested pseudo rules inside a media query

You can still use the psuedo.prop:val syntax inside a media query rule set, they will only apply when the breakpoint is active

<i hw="hover.color:white, after.content:'small' 
  @md:{ hover.color:black, after.content:'medium' }
">

Nesting pseudo rules inside pseudo rules

What if you want to style the hover of a disabled button?

<button hw="color:red, 
  hover:{ color:blue, text-decoration:underline }, 
  disabled:{ color:grey, text-decoration:none, 
    hover:{ color:brown, text-decoration:strike-through }
  }
">

Even more nesting

Again if you want to do a few things on hover, or with some other pseudo class/element, you can nest a set of rules inside the media query rules. These will only apply on hover when the parent media query is active

<p hw="@lg:{ 
    color:red, text-decoration:underline, 
    hover:{ color:blue, text-decoration:none }
  }
">

Output

Currently Headwind only supports outputting a headwind.css file, no <style> injection yet.

Headwind will only generate CSS rules that are actually needed. The rules are a bit verbose, but its still much lighter, and faster to build, than tailwind, and doesnt require purging

For example this obviously ridiculous set of rules (seriously dont do this)

<h1 class="normal-class" hw="w:1/4, mb:1.5, bg-img:'url(hello.jpg)', color:grey, hover.color:white, after.color:red,
  after: { content:'after small', color:grey, hover: { color:brown, font-weight:light }},
  @md: { color:teal, hover.color:orange, after:{ color:white, content:'after medium', hover.color:teal }}, 
  @lg:{ color:blue, after: {content:'after large', color:purple, hover.color:pink}, hover.color:yellow }">

<span hw="color:grey, width:100%, after.content:'after small'">

builds to this HTML/CSS (CSS is minified but newlines added here for legibility).

<h1 class="normal-class width-25_1 margin-bottom-1-5rem_2 background-image-url-hello-jpg-_3 color-grey_4 color-white_5 color-red_6 content-after-small_7 color-brown_8 font-weight-light_9 md-color-teal_10 md-color-orange_11 md-color-white_12 md-content-after-medium_13 lg-color-blue_14 lg-content-after-large_15 lg-color-purple_16 lg-color-pink_17 lg-color-yellow_18">

<span class="color-grey_4 width-100_19 content-after-small_7">
.width-25_1{width:25%}
.margin-bottom-1-5rem_2{margin-bottom:1.5rem}
.background-image-url-hello-jpg-_3{background-image:'url(hello.jpg)'}
.color-grey_4{color:grey}
.color-grey_4::after{color:grey}
.color-white_5:hover{color:white}
.color-red_6::after{color:red}
.content-after-small_7::after{content:'after small'}
.color-brown_8:hover::after{color:brown}
.font-weight-light_9:hover::after{font-weight:light}
.width-100_19{width:100%}
@media screen and (min-width:1024px){
.md-color-teal_10{color:teal}
.md-color-teal_10:hover::after{color:teal}
.md-color-orange_11:hover{color:orange}
.md-color-white_12::after{color:white}
.md-content-after-medium_13::after{content:'after medium'}
}
@media screen and (min-width:1600px){
.lg-color-blue_14{color:blue}
.lg-content-after-large_15::after{content:'after large'}
.lg-color-purple_16::after{color:purple}
.lg-color-pink_17:hover::after{color:pink}
.lg-color-yellow_18:hover{color:yellow}
}

If multiple elements use the same prop:value pairs, they wont get added multiple times to the generated CSS. The trailing _1 is to ensure that 2 rules that slugify to the same string wont interfere with each other, but every element that uses color:grey will be assigned the class .color-grey_4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment