Solving Layout Challenges with
Pure Sass

(a talk by @AhoyLemon)

Solving Layout Challenges with
Pure Sass

(a talk by @AhoyLemon)

Solving Layout Challenges with
Pure Sass

(a talk by @AhoyLemon)

Hi!

My name is Lemon.

(I make websites.)

I work at

Savas Labs

Front End
Development Director

  • Mentoring
  • Shepherding
  • Documenting
THIS IS ME NOW
THIS WAS ME THEN

So, I took a contract

We have this legacy software platform, which was built in Ruby on Rails, and has a lot of problems, both visually and with general reliability.

We want to rebuild this entire platform in .NET, and we have the backend part of it figured out, but we need somebody to do the frontend, hopefully very quickly.

The Client

So, I built a frontend.

built it in a month.

They offered me full time.

Now we got a problem...

This is Jeff.
Jeff overcomplicates things.
Jeff is your enemy.

Now let's talk about frameworks.

We need a new website!

The Client

Okay, that means we need a framework.

Jeff

Bootstrap

getbootstrap.com(CSS & Vanilla JS)

Foundation

get.foundation(CSS & Vanilla JS)

Cirrus

cirrus-ui.netlify.app(CSS Only)

Element+

element-plus.org(Vue 3)

Material

MUI Core (React)
Angular Material (Angular 2+)
Vuetify(Vue)
Materialze CSS(Sass & JS)

Carbon

carbondesignsystem.com(React, Vue or Angular)
* but realistically, probably just React.

Primer

primer.style(CSS Only)

And like, a whole lot more...

  • Metro UI
  • Montage
  • Onsen UI
  • YUI
  • Topcoat
  • Jeet
  • Ink
  • Kickstart
  • etc etc etc

this framework is deprecated

This is not a talk about frameworks.

This is a talk about...

This is a talk about...

This is a talk about...

&

But first, a word about...

  • is something I like to use
  • is presented here for brevity
  • is not a requirement

Viewport Units

(vw & vh)

div { width: ...;  }
code Result
500px 500 pixels wide
50% 50% of the container
66em 66 letters
current font size
66rem 66 letters
base font size
1fr 1 fraction of the remaining width
this is grid-specific
50vw 50% of the viewport width
50vh 50% of the viewport height

The Objective

We like that Apple design where the whole screen is just a single slide and then when you scroll down you see another slide.

The Client

Okay, let's write a bunch of javascript to make that work

Jeff

HTML

ㅤㅤ
...
ㅤㅤ
...
ㅤㅤ
...

Scss

main {
ㅤsection { min-height: 100vh;  }
}

We also added this...

section { 
ㅤdisplay: flex; align-items:center; justify-content:center;
}

AND THIS

main { scroll-snap-type: y proximity; }
section {
ㅤdisplay: flex; align-items:center; justify-content:center;
ㅤscroll-snap-align: start;
}

open in new window

Okay, that's nice, but now I want the sections to have backgrounds, but the background should move separately from the foreground, and also put a gradient in there.

kthxbye!

The Client

Parallax!? We need javascript for that!

Jeff

WE HAD THIS

main { scroll-snap-type: y proximity; }
section {
ㅤmin-height: 100vh;
ㅤdisplay: flex; align-items:center; justify-content:center;
ㅤscroll-snap-align: start;
ㅤalign-items:center;
}

LET'S ADD THIS

main { scroll-snap-type: y proximity; }
section {
ㅤmin-height: 100vh;
ㅤㅤdisplay: flex; justify-content:center;
ㅤscroll-snap-align: start;
ㅤalign-items: flex-end;
ㅤbackground-attachment: fixed; 
ㅤbackground-size:cover; background-position: center; 
ㅤ.content { position: relative;
ㅤㅤ&:before { content:'';
ㅤㅤㅤposition:absolute; top:0; bottom:0; right:0; left:0;
ㅤㅤㅤbackground:linear-gradient(rgba(0,0,0,0), rgba(0,0,0,0.95));
ㅤㅤ}
ㅤ}
}

AND OUR HTML

ㅤㅤ
ㅤㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤ... ㅤㅤㅤㅤㅤㅤ
ㅤㅤㅤㅤ
ㅤㅤ

Grid Layouts

We need to build a brand new website. It's gonna have a topnav and then we have to have a side rail as well because we have a lot of content, and obviously a footer.

The Client

A whole site layout? We're gonna need a framework for that!

Jeff

HTML

...
...
...

Scss

.layout { display:grid; grid-template-columns: 260px 1fr;
ㅤheader, footer { grid-column: span 2 ; }
}

We also coulda done this...

.layout {
ㅤdisplay:grid;
ㅤgrid-template-columns: 260px 1fr;
ㅤgrid-template-areas: 
ㅤㅤ"header header"
ㅤㅤ"aside main"
ㅤㅤ"footer footer";
ㅤheader { grid-area: header; }
ㅤaside  { grid-area: aside; }
ㅤmain   { grid-area: main; }
ㅤfooter { grid-area: footer; }
}

Repeating Grids

Thanks for the website layout! Okay, now we have to have a page with a bunch of blog teasers. We're gonna show an image and the headline and some tags, probably some other stuff too, and we don't know how many there's gonna be.

Oh, and obviously it has to be responsive for all screensizes.

The Client

Let's see which frontend framework will work with this.

Jeff

HTML

...
...
...
ㅤ...

Scss

.cards { display: grid; row-gap:60px; column-gap:10px; 
ㅤ@media (min-width: 980px)  { grid-template-columns: repeat(3,1fr); }
ㅤ@media (max-width: 979px)  { grid-template-columns: repeat(2,1fr); }
ㅤ@media (max-width: 580px)  { grid-template-columns: repeat(1,1fr); }
ㅤ.card { display:grid; grid-template-columns: 1fr; gap:$padding; }
}

But let's keep going...

So, our card

.card { display:grid; gap:$padding;

  ㅤgrid-template-columns: 1fr; 
  ㅤ.headline { font-size:1.15rem; }
  ㅤfigure { margin-top:-2em; }

}

So, our card

.card { display:grid; gap:$padding;
ㅤ@media (min-width:$min-width) {
ㅤㅤgrid-template-columns: 1fr; 
ㅤㅤ.headline { font-size:1.15rem; }
ㅤㅤfigure { margin-top:-2em; }
ㅤ}
ㅤ@media (min-width:$alt-card-min) and (max-width: $alt-card-max)  {
ㅤㅤgrid-template-columns: 210px 1fr 160px;
ㅤㅤ.headline { font-size:clamp(1rem,4.5vw,1.7rem); }
ㅤㅤ// ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ  ☝️ we'll get back to this one.
ㅤㅤfigure { margin-left: -20px; margin-top:unset; grid-row: span 2; }
ㅤㅤ.headline, .author { grid-column: span 2; }
ㅤㅤ.summary { grid-column: span 3; }
ㅤㅤ.tags { grid-column: span 2; }
ㅤ}
}

Nearly there! We really like it, but...

We want to alternate every other card, so the first one image on the left headline on the right. Second one, image on the right headline on the left.

Oh but also? Every other card, we actually want to swap around the author and dates?

I WILL NOT EXPLAIN MY REASONS 😡

kthxbye!

The Client
.card:nth-child(even) { grid-template-columns: 1fr 210px;
ㅤ.headline { order: 1; }
ㅤfigure { order: 2; margin-right:-20px; }
ㅤ.publish-date { order: 3; }
ㅤ.summary { order: 4; }
ㅤ.tags { order: 5; }
ㅤ.author { order: 6; }
}

Hmmmmmmm, I just realized, all of these are links, but we don't have any hover action in there.

Okay, so we want it where when you hover on the image, the title goes orange, but also? The card gets bigger, and it goes up a bit?

Okay, first let's get Jeff to do this

the wrong way.

.card {
ㅤtransform: all 0.3s ease;
ㅤ&:hover {
ㅤㅤmargin-top:-20px; margin-left:-20px; margin-right:-20px;
ㅤ}
}

it's time for

transform

.card:hover { transform:...  }

Some Transforms

transform: translateX($x);
transform: translateY($y);
transform: translateZ($z);
transform: translate($x,$y);
transform: translate3d($x,$y,$z);
transform: scale($amount);
transform: scale($x,$y);
transform: scale3d($x,$y,$z);
transform: rotate($degrees);
transform: skew($angleX,$angleY);
transform: perspective($amount);
transform: matrix($a, $b, $c, $d, $tx, $ty)

So, therefore...

.card {
ㅤtransition: box-shadow 0.3s linear, transform 0.3s ease;
ㅤ&:hover {
ㅤㅤbox-shadow: $card-shadow;
ㅤㅤtransform: scale(1.08) translateY(-8%); z-index: $z-topcard;
ㅤ}
}

Another design for you to look at!

CSS Clamp

font-size: clamp($min,$baseline,$max);
article {
  .inner {  font-size: clamp(16px, 2.4vw, 22px);
            max-width: 66ch; margin-left:auto; margin-right:auto;
    h1 { font-size: clamp(32px, 4.7vw, 76px); }
    h2 { font-size: clamp(26px, 3.8vw, 66px); }
    h3 { font-size: clamp(18px, 3vw, 56px); }
    h1, h2, h3 { font-weight:$bold; font-family:$headline-font; }
  }
}

We need a form!

Jeff can make it!

Jeff's form

Our form

and our css

fieldset {
ㅤdisplay:grid; grid-template-columns: 1fr;
ㅤinput, select { border:3px solid $form-inactive; order:2; }
ㅤlabel { order: 1; }
ㅤ&:hover {
ㅤㅤlabel { color:$blue; }
ㅤㅤinput, select { border-color:$form-active; }
ㅤ}
ㅤinput, select {
ㅤㅤ&:focus { border-color: $form-active;
ㅤㅤㅤ~ label { color:$form-active; }
ㅤㅤ}
ㅤ}
}

Speed Round!

iframe {
ㅤaspect-ratio: 16/9;
}

.content-with-rail  { display:grid; grid-template-columns: 1fr 200px;
ㅤ.rail-holder { position: relative;
ㅤㅤ.rail { position:sticky: top:$gap; }
ㅤ}
}
.parallelogram {
ㅤclip-path: polygon(0 20%, 100% 0%, 100% 80%, 0% 100%);
}
.ellipse {
ㅤclip-path: ellipse(50% 25% at 50% 50%);
}
.inset {
ㅤclip-path: inset(5% 20% 15% 10%);
}
.heart { 
ㅤclip-path: path('M213.1,6.7c-32.4-14.4-73.7,0-88.1,30.6C110.6,4.9,67.5-9.5,36.9,6.7C2.8,22.9-13.4,62.4,13.5,110.9 C33.3,145.1,67.5,170.3,125,217c59.3-46.7,93.5-71.9,111.5-106.1C263.4,64.2,247.2,22.9,213.1,6.7z');
}
.notch-right {
ㅤfloat:right; margin-left:1em; margin-bottom:1em; 
ㅤshape-outside: polygon(100% 0, 0 0, 100% 100%);
}
.notch-left {
ㅤfloat:left; margin-right:1em; margin-bottom:1em; 
ㅤshape-outside: polygon(100% 0, 0 0, 0 100%);
}
.ellipse-left {
ㅤfloat:left; padding-right:1em;
ㅤshape-outside: ellipse();
}

So, where do you go from here?

Get cooking!

A Complete Guide to CSS Grid
A Complete Guide to Flexbox

Bennett Feely's

This Talk!

ahoylemon.github.io/pure-sass

🤙🏻 hit me up

Training, mentoring, advice, etc
Mail.Ru lemon@ahoylemon.xyz
Twitter [deprecated]
Mastodon @ahoylemon@mastodon.social
Sessionize Sessionize.com/lemon
GitHub github.com/AhoyLemon
Find me, I'm around.

Thank you.

ahoylemon.xyz