Sunday, October 2, 2016

CSS Responsive Mini-framework with Resizable sections

This is an experimental Sass/CSS mini-framework for building responsive sites with Resizable (Zoomable?) sections.

Resizable sections enlarge proportionally with the viewport size. These areas are based on relative CSS units as explained in Building Resizeable Components with Relative CSS Units.

I also wanted to have a minor-font-size-scaling, a small font increase that would apply to everything in the page.

Breakpoints are at regular interval. They can be customized but for the example below I have the first breaking point at 34em (544px) and the next with interval of 14em (224px).

The other breaking points are at 48em (768px), 62em (992px), 76em (1216px) and 90em (1440px).


For the minor-font-size-scaling I decided to go with half pixel for each section. In the interval between 768px and 992px, the font-size will be 1em = 16px. For the smallest viewport (<544px) it will go down to 15px (16px - 0.5px * 2)

All this is generated from these four variables that can be customized:

$browser-context-px:        16.0px //  1em
$breakpoints-start-px:     320.0px // 20em
$breakopints-increment-px: 224.0px // 14em
$font-size-increment-px:     0.5px

$browser-context-px is the ratio between px and em. In this case I am using the default 1:16

Both breakpoints and font sizes at each level are generate by these two functions:

@function breakpointPx($level)
  // Breakpoints generator
  @return $breakpoints-start-px + $breakopints-increment-px * $level
@function fontSizePx($level)
  // Font-sizes generator
  @return $font-size-start-px + $font-size-increment-px * $level

Is possible to define minimum font sizes using the function minFontSizeEm. This is useful in case we want to be sure that no font ever goes below to certain size at any viewport format. For example a font that should never be smaller than 14px, also on the smallest viewport size, should be

@function minFontSizeEm($sizePx)
  // Minimum size of font for screen  = 320px
  @return (($sizePx / 1px) * ( 1px / emtopx(fontSizeEm(1)))) * 1em

That is, given the variables above:

14 / 15 = 0.93333em

Where 14 is the minimum font size we want to get and 15 is the size of the default font on the smaller viewport format.

To create the zooming sections we set a font-size using relative units (vw) and then we define any other size using the unit em. The vw unit is 1/100 the width of the viewport. You can find more info on this unit in mozilla.org/en/docs/Web/CSS/length. To calculate the proper number for the vw unit there is this function:

@function zoomingFontSizeVw($zoom-starting-level)
  @return ( ( fontSizeEm( $zoom-starting-level + 1 ) * 100 ) /
    breakpointEm( $zoom-starting-level ) ) * 1vw

The function take in consideration from which level the zoom is starting from and the minor-font-size-scaling that is already in place. So, for example, having a section with

font-size: zoomSizeVw(0)

will make the section resizable from 0 to infinite, proportionally at the viewport size. Moreover at the viewport size of 320 pixels, all fonts will match their smallest size as defined in the minFontSizeEm function.

Is interesting to note that if we want to start the zoom at a different breakpoint, we need to specify in the parameter of the zoomSizeVw function because the zoom "ratio" will be different.

To avoid the zoomed text going too small at viewport sizes < 320px is possible to use the smallest breakpoint, like in:

.className
  @media (min-width: breakpointEm(0))
    font-size: zoomSizeVw(0)

This will be compiled as

@media (min-width: 20em) {
  .className {
    font-size: 4.6875vw;
  }
}

To give an upper limit to the zoom is a bit more complicated because we need to calculate the size that the font reached at that point. We also need to take in consideration the minor-font-size-scaling that can be different when the zooming started and when the zooming ended.

For this calculation there is another function that return the font size reached after the zooming. The function is

@function fixedFontSizeRem($zoom-starting-level, $zoom-ending-level)
  @return ((( zoomingFontSizeVw($zoom-starting-level) / 1vw) *
    (breakpointEm($zoom-ending-level) / 1em)) / 100) / 
      (fontSizeEm($zoom-ending-level + 1) / 1em) * 1rem

This function require two parameters, one for the zoom-starting-level because depending on from where the zoom started from, it has a different increasing ratio. The other parameter is the zoom-ending-level.

So for a section that we want to zoom but with a lower and upper limit we can specify:

.nAnnnnn
  @media (min-width: breakpointEm(0))
    font-size: zoomSizeVw(0)
  @media (min-width: breakpointEm(1))
    font-size: fixedSizeRem(0, 1)

To give classes a meaningful name I used a series of letters. Each letter indicates the state on each interval between breakpoints. The first letter is for the area < 320px, the last letter for the area > 1440px. The letter n means that in the area the font size is "normal", flat. A capital letter "ABCDE" means that in the area the font is zooming. The letter indicate the starting point of zooming. If a letter is duplicate it just simply means that the font keep zooming. So for example

nAnnnnn

means that the font is only zooming between 320px and 544px.

nAAAAAn

means that the font is zooming from 320px to 1440

to have the section zooming from 544px we need to use the letter B, as in:

nnBnnnn

One possible combination is:

nABCDEn

In this case the font is zooming in each interval but the zooming start from 0 at the beginning of the interval. This can be used in case we have items in a grid and at each breaking point we squeeze the grid to make one more item to fit in the row.

Another option is when we want to have a resizable section that at certain point goes from one column to two columns. That could look something like:

nAACCCn

This one will zoom until 768px and then reset the zoom to 0. It would also possible to reset the zoom to a different zoom type:

nAABBBn

important is not to use a zoom level before the right time. For example

nBnnnnn

would make font going below the minimum size because the "B" is in the position where the "A" should be.

"nABCDEn" combination can be generated with these Sass lines:

.nABCDEn
  @media (min-width: breakpointEm(0))
    font-size: zoomingFontSizeVw(0)
  @media (min-width: breakpointEm(1))
    font-size: zoomingFontSizeVw(1)
  @media (min-width: breakpointEm(2))
    font-size: zoomingFontSizeVw(2)
  @media (min-width: breakpointEm(3))
    font-size: zoomingFontSizeVw(3)
  @media (min-width: breakpointEm(4))
    font-size: zoomingFontSizeVw(4)
  @media (min-width: breakpointEm(5))
    font-size: fixedFontSizeRem(4,5)

The possible combinations are a lot so I generated only the combinations that I need in the site that I am building.

I am sure there are better and simpler way to tackle this type of requirements but this was my best option so far.

Here there is a graphical representation of the framework with some of the values in it. In the case below the minor-font-size-scaling is disabled ($font-size-increment-px: 0px)


Here is the case where $font-size-increment-px: 0.5px. Note that the graph is not geometrically correct.



This is how the examples render at different viewports:




You can find the Sass code and examples here (you can check the Debug Mode of the Pen to see a full page test):

No comments :

Post a Comment