CSS - tutorial - 27 - positioning

Revision:


Content

CSS positioning position controls relativity indicator z-index anchor positioning how to get rid of a floating footer?

CSS positioning

Positioning allows to take elements out of normal document flow and make them behave differently, for example, sitting on top of one another or always remaining in the same place inside the browser viewport.

syntax : position: static | relative | absolute | sticky | fixed

        position: static;
        position: relative;
        position: absolute;
        position: fixed;
        position: sticky;

        /* Global values */
        position: inherit;
        position: initial;
        position: revert;
        position: revert-layer;
        position: unset;
    

static positioning

The element is positioned according to the "normal flow" of the document. The "top", "right", "bottom", "left", and "z-index" properties have no effect. This is the default value.

example

            <p class="positioned">…</p>
            <style>
                .positioned {
                    position: static;
                    background: yellow;
                }
            
        

relative positioning

The element is positioned according to the normal flow of the document, and then offset relative to itself based on the values of "top", "right", "bottom", and "left". The offset does not affect the position of any other elements; thus, the space given for the element in the page layout is the same as if position were static.

This value creates a new stacking context when the value of "z-index" is not auto. Its effect on "table-*-group", "table-row", "table-column", "table-cell", and "table-caption" elements is undefined.

example

        <p class="positioned">…</p>
        <style>
            .positioned {
                position: relative;
                background: yellow;
            }
        
    

absolute positioning

The element is removed from the normal document flow, and no space is created for the element in the page layout. The element is positioned relative to its closest positioned ancestor (if any) or to the initial containing block. Its final position is determined by the values of "top", "right", "bottom", and "left".

This value creates a new stacking context when the value of "z-index" is not auto. The margins of absolutely positioned boxes do not collapse with other margins.

example

        <p class="positioned">…</p>
        <style>
            .positioned {
                position: absolute;
                background: yellow;
            }
        
    

fixed positioning

The element is removed from the normal document flow, and no space is created for the element in the page layout. The element is positioned relative to its initial containing block, which is the viewport in the case of visual media. Its final position is determined by the values of "top", "right", "bottom", and "left".

This value always creates a new stacking context. In printed documents, the element is placed in the same position on every page.

example

        <p class="positioned">…</p>
        <style>
            .positioned {
                position: fixed;
                background: yellow;
            }
        
    

sticky positioning

The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor), including table-related elements, based on the values of "top", "right", "bottom", and "left". The offset does not affect the position of any other elements.

This value always creates a new stacking context. Note that a sticky element "sticks" to its nearest ancestor that has a "scrolling mechanism" (created when overflow is hidden, scroll, auto, or overlay), even if that ancestor isn't the nearest actually scrolling ancestor.

        <p class="positioned">…</p>
        <style>
            .positioned {
                position: sticky;
                background: yellow;
            }
        
    

position controls

top

For elements with "absolute" and "fixed" positions, presets allow to position the element relative to the element indicated in the relativity indicator (see below).

Any of the following preset positions can be chosen:

Top left: sets the following values: top: 0px - left: 0px
Top right: sets the following values: top: 0px - right: 0px
Bottom left: sets the following values: bottom: 0px - left: 0px
Bottom right: sets the following values: bottom: 0px - right: 0px
Left: sets the following values: top: 0px - left: 0px - bottom: 0px
Right: sets the following values: top: 0px - right: 0px - bottom: 0px
Top: sets the following values: top: 0px - left: 0px - right: 0px
Bottom: sets the following values: bottom: 0px - left: 0px - right: 0px
Full: sets the following values: top:0px - bottom: 0px - left: 0px - right: 0px (covers the entire relative parent or body)

The manual controls allow to override the presets or default to the auto value for the top, bottom, left, and right side. The value for each side can be changed either by dragging the control or clicking it and choosing a preset value or entering a custom value.

Top: increase it to push the element down from the top
Left: increase it to push the element off from the left and move it to the right
Right: increase it to push the element off from the right and move it to the left
Bottom: increase it to push the element up from the bottom

Adding negative values for any of these will move it in the opposite direction and may push it out of the border of the parent element.


relativity indicator

top

The relativity indicator shows which element a selected element is positioned relative to.

An element set to relative positioning is positioned relative to itself.

An element set to absolute element is positioned relative to a parent element. By default, this might be the body element. If you want to absolutely position an element within a specific parent, change the position of that ancestor to anything but static.

A fixed element is positioned relative to the page body and remains in place even when the page is scrolled.

A sticky element is positioned relative to its direct parent element. In some cases, this will be the page body.


z-index

top

The Z-index is an element's position on the imaginary z-axis extending into and out of the computer screen.

By default, elements have an auto z-index.
Elements at the bottom of the page stack above elements above them.
Elements on the right stack above elements to the left.
Static elements always stack lower than positioned elements with a position set to relative, absolute, fixed, or sticky.

Positioned elements may overlap other elements in the natural document flow, therefore the Z-index value of any positioned element can be altered to change its default stacking order.

Higher values stack on top of lower values.
Z-index values can be any integer from 0 to 2147483647.
Negative values can be used, but element visibility can be lost as the element will get rendered underneath most elements.

Z-index on nested elements

When the z-index is set to auto, the stack order of the element is equal to its parent's stack order.
These elements can be stacked relative to the parent element but remain within the parent element's z-axis relative to other elements.
For example, if element A has a higher z-index than an element B, a child element of element B can never be higher than element A no matter how high the z-index value of element B is.


anchor positioning

Anchor positioning allows you to place items relative to where another element is. You declare an element an anchor and give it a name, then elements can be positioned to the top/right/bottom/left (or center, or the logical equivalents) of the anchor.

CSS Anchor Positioning gives us a simple interface to attach elements next to others just by saying which sides to connect — directly in CSS. It also lets us set a fallback position so that we can avoid the overflow issues.

Some concepts to keep in mind :

containing block : this is the box that contains the elements. For an absolute element, the containing block is the viewport the closest ancestor with a position other than static or certain values in properties like "contain" or "filter".

inset-modified containing block (IMCB): : for an absolute element, "inset" properties (top, right, bottom, left, etc.) reduce the size of the containing block into which it is sized and positioned, resulting in a new box called the inset-modified containing block, or IMCB for short. This is a vital concept to know since properties — like "position-area" and "position-try-order" — rely on this concept.

CSS anchor positioning module

This module defines features that allow you to tether elements together. Certain elements are defined as anchor elements (= anchor); anchor-positioned elements (=target) can then have their size and position set based on the size and location of the anchor elements to which they are bound.

To associate an element with an anchor, you need to first declare which element is the anchor, and then specify which positioned element(s) to associate with that anchor. This can be done via CSS or via the HTML "anchor" attribute.

CSS-only method:

to declare an element as "an anchor" with CSS, you need to set an anchor name on it via the "anchor-name" property. The anchor name needs to be a <dashed-ident>.

        anchor {
            anchor-name: --myAnchor;
            width: fit-content;
        }
    

converting an element to an anchor-positioned element requires two steps: 1/ it needs to be "absolutely" or "fixed" positioned using the "position" property; 2/ the positioned element then has its "position-anchor" property set to the value of the anchor element's "anchor-name" property to associate the two together

        .infobox {
            position: fixed;
            position-anchor: --myAnchor;
        }
   

HTML method:

To associate a positioned element with an anchor in HTML, you can use the "anchor" attribute. You need to give the anchor element an "id". The anchor attribute is then set on the anchor-positioned element, with a value equal to the id of the anchor element you want to associate it with.

        <div class="anchor" id="example-anchor">⚓︎</div>
        <div class="infobox" anchor="example-anchor">
            <p>This is an information box.</p>
        </div>
    

Elements need to be "absolutely" or "fixed" positioned to be associated with anchors,

        <style>
            .infobox {
                 position: fixed;
            }
        </style>
    

In addition, the specification provides CSS-only mechanisms to:

specify a set of alternative positions for an anchored element ; when the default rendering position causes it to overflow its containing block and/or be rendered offscreen, the browser will try rendering the anchored element in the alternative positions instead.

declare conditions under which anchor-positioned elements should be hidden, in situations where it is not appropriate to tether them to anchor elements.

properties

anchor-name : enables defining an element as an anchor element by giving it one or more identifying anchor names.

syntax : anchor-name: none || <dashed-ident>

            /* Single values */
            anchor-name: none;
            anchor-name: --name;

            /* Multiple values */
            anchor-name: --name, --another-name;

            /* Global values */
            anchor-name: inherit;
            anchor-name: initial;
            anchor-name: revert;
            anchor-name: revert-layer;
            anchor-name: unset;
        

Values:

none : default value. Setting "anchor-name: none" on an element means that it is not defined as an anchor element. If the element was previously defined as an anchor and associated with a positioned element, setting "anchor-name: none" disassociates the two.
<dashed-ident> : one or more comma-separated arbitrary custom identifiers defining the name or names of the anchor, which can then be referenced in a "position-anchor" property.

position-anchor : specifies the anchor name of the anchor element (i.e. an element that has an anchor name set on it via the "anchor-name" property) a positioned element is associated with.

syntax : position-anchor: auto || <anchor-name> (= <dashed-ident>)

            /* Single values */
            position-anchor: auto;
            position-anchor: --anchorName;
            
            /* Global values */
            position-anchor: inherit;
            position-anchor: initial;
            position-anchor: revert;
            position-anchor: revert-layer;
            position-anchor: unset;
        

Values:

auto : associates a positioned element with its implicit anchor element, if it has one — for example as set by the non-standard HTML "anchor" attribute.
<dashed-ident> : the name of the anchor element to associate the positioned element with, as listed in the anchor element's "anchor-name" property. This is known as the default anchor specifier.

position-area : enables an anchor-positioned element to be positioned relative to the "edges of its associated anchor element" by placing the positioned element on one or more tiles of an implicit 3x3 grid, where the anchoring element is the center cell.

this is an experimental technology

syntax: position-area: none || <position-area>

            /* Default value */
            position-area: none;

            /* Two  keywords defining a single specific tile */
            position-area: top left;
            position-area: start end;
            position-area: block-start center;
            position-area: inline-start block-end;
            position-area: x-start y-end;
            position-area: center y-self-end;

            /* Two  keywords spanning two tiles */
            position-area: top span-left;
            position-area: center span-start;
            position-area: inline-start span-block-end;
            position-area: y-start span-x-end;

            /* Two  keywords spanning three tiles */
            position-area: top span-all;
            position-area: block-end span-all;
            position-area: x-self-start span-all;

            /* One  keyword with an implicit second  keyword  */
            position-area: top; /* equiv: top span-all */
            position-area: inline-start; /* equiv: inline-start span-all */
            position-area: center; /* equiv: center center */
            position-area: span-all; /* equiv: center center */
            position-area: end; /* equiv: end end */

            /* Global values */
            position-area: inherit;
            position-area: initial;
            position-area: revert;
            position-area: revert-layer;
            position-area: unset;
      
    

Values:

<position-area> : specifies the area of the position area grid on which to place selected positioned elements.
none : no position area is set.

position-try-fallbacks : enables you to specify a list of one or more alternative "position try fallback" options for anchor-positioned elements to be placed relative to their associated anchor elements. When the element would otherwise overflow its inset-modified containing block, the browser will try placing the positioned element in these different fallback positions, in the order provided, until it finds a value that stops it from overflowing its container or the viewport.

this is an experimental technology

syntax: position-try-fallbacks : none || <try-tactic> || <position-area> || <dashed-ident>

            * Default value: no try fallback options */
            position-try-fallbacks: none;

            /* Single try option */
            position-try-fallbacks: flip-block;
            position-try-fallbacks: top;
            position-try-fallbacks: --custom-try-option;

            /* Multiple value combination option */
            position-try-fallbacks: flip-block flip-inline;

            /* Multiple values */
            position-try-fallbacks: flip-block, flip-inline;
            position-try-fallbacks: top, right, bottom;
            position-try-fallbacks: --custom-try-option1, --custom-try-option2;
            position-try-fallbacks:
            flip-block,
            flip-inline,
            flip-block flip-inline;
            position-try-fallbacks:
            flip-block,
            --custom-try-option,
            --custom-try-option flip-inline,
            right;

            /* Global values */
            position-try-fallbacks: inherit;
            position-try-fallbacks: initial;
            position-try-fallbacks: revert;
            position-try-fallbacks: revert-layer;
            position-try-fallbacks: unset;
    

Values:

none : the default value. There are no "position try fallback" options set.
<try-tactic> : predefined fallback options move the positioned element by taking its computed position and transforming it across a particular axis of the anchor, mirroring any margin offsets. Possible values are: 1/flip-block : flips the element's position along the block axis; 2/ flip-inline : flips the element's position along the inline axis; 3/ flip-start : flips both the inline and block axis values, swapping the start properties with each other, and the end properties with each other.
position-area value : positions the element relative to the edges of its associated anchor element by placing the positioned element on one or more tiles of an implicit 3x3 position area grid based on the specified <position-area> value; the effect is the same as a custom "@position-try fallback" option containing only a position-area descriptor.
<dashed-ident> : adds a custom "@position-try option" to the fallback options list, the identifying name of which matches the specified dashed-ident. If no custom position option exists with that name, the option is ignored.

position-try-order : allows to specify various fallback options that result in an available position-try fallback being used to set an anchor-positioned element's position, instead of its initial position settings.

syntax: position-try-order : normal || <try-size>

            /* Keywords */
            position-try-order: normal;
            position-try-order: most-height;
            position-try-order: most-width;
            position-try-order: most-block-size;
            position-try-order: most-inline-size;

            /* Global values */
            position-try-order: inherit;
            position-try-order: initial;
            position-try-order: revert;
            position-try-order: revert-layer;
            position-try-order: unset;
    

Values:

normal : the default. No position-try fallback options will be tried when the element is first displayed.
<try-size> : defines the different try size fallback options, which specify criteria that determine what try fallback should be applied to the anchor-positioned element when it initially renders. Available values are: 1/ most-height : the position try fallback option will be applied that gives the element's containing block the most height; 2/ most-width : the position try fallback option will be applied that gives the element's containing block the most width; 3/ most-block-size : the position try fallback option will be applied that gives the element's containing block the largest size in the block direction; 4/ most-inline-size : the position try fallback option will be applied that gives the element's containing block the largest size in the inline direction.

position-try shorthand : corresponds to the "position-try-order" and "position-try-fallbacks" properties.

syntax:position-try : <position-try-order> <position-try-fallbacks>

            /* position-try-fallbacks only */
            position-try: normal flip-block;
            position-try: top;
            position-try: --custom-try-option;
            position-try: flip-block flip-inline;
            position-try: top, right, bottom;
            position-try: --custom-try-option1, --custom-try-option2;
            position-try:
            normal flip-block,
            right,
            --custom-try-option;
            
            /* position-try-order and position-try-fallbacks */
            position-try: normal none;
            position-try:
            most-width --custom-try-option1,
            --custom-try-option2;
            position-try:
            most-height flip-block,
            right,
            --custom-try-option;
            
            /* Global values */
            position-try: inherit;
            position-try: initial;
            position-try: revert;
            position-try: revert-layer;
            position-try: unset;
    

Values:

See "position-try-order" and "position-try-fallbacks" for value descriptions. The "position-try shorthand" can specify values for "position-try-fallbacks", or "position-try-order" and "position-try-fallbacks", in that order. If "position-try-order" is omitted, it is set to the property's initial value, which is normal, meaning the position-try fallback options are tried in the order they appear in the property.

position-visibility : enables conditionally hiding an anchor-positioned element depending on, for example, whether it is overflowing its containing element or the viewport.

this is an experimental technology

syntax: position-visibility: always || anchor-visible || no-overflow || anchor-valid

            /* Single values */
            position-visibility: always;
            position-visibility: anchors-visible;
            position-visibility: no-overflow;

            /* Global values */
            position-visibility: inherit;
            position-visibility: initial;
            position-visibility: revert;
            position-visibility: revert-layer;
            position-visibility: unset;
    

Values:

always : the positioned element is always displayed;
anchors-visible : if the anchor is completely hidden, either by overflowing its containing element (or the viewport) or being covered by other elements, the positioned element will be strongly hidden;
no-overflow : if the positioned element starts to overflow its containing element or the viewport, it will be strongly hidden;
anchor-valid: not yet implemented in any browser.

at rules and descriptors

@position-try : used to define a custom position try fallback option, which can be used to define positioning and alignment for anchor-positioned elements. One or more sets of position try fallback options can be applied to the anchored element via the "position-try-fallbacks property" or "position-try shorthand". When the positioned element is moved to a position where it starts to overflow its containing block or the viewport, the browser will select the first position try fallback option it finds that places the positioned element fully back on-screen.

Each position option is named with a <dashed-ident> and contains a descriptor list specifying declarations that define information such as inset position, margin, sizing, and self-alignment. The <dashed-ident> is used to reference the custom position option in the "position-try-fallbacks" property and "position-try" shorthand.

syntax:

@position-try --try-option-name {
                                        descriptor-list
                                }
       

functions

anchor() : can be used within an anchor-positioned element's "inset property values", returning a length value relative to the position of the edges of its associated anchor element.

syntax : anchor(<anchor-name> <anchor-side>, <length-percentage>)

        /* side or percentage */
        top: anchor(bottom);
        top: anchor(50%);
        top: calc(anchor(bottom) + 10px)
        inset-block-end: anchor(start);
        
        /* side of named anchor */
        top: anchor(--myAnchor bottom);
        inset-block-end: anchor(--myAnchor start);
        
        /* side of named anchor with fallback */
        top: anchor(--myAnchor bottom, 50%);
        inset-block-end: anchor(--myAnchor start, 200px);
        left: calc(anchor(--myAnchor right, 0%) + 10px);
    

Parameters:

<anchor-name> : optional. The "anchor-name property value" of an anchor element you want to position the element's side relative to. This is a <dashed-ident> value. If omitted, the element's default anchor, referenced in its "position-anchor" property, or associated with the element via the "anchor" HTML attribute, is used.

<anchor-side> : specifies the side of the anchor, or the relative distance from the start side, which the element is positioned relative to. If a physical or logical value is used that is not compatible with the "inset" property on which anchor() is set, the fallback value is used. Valid values include:

top : The top of the anchor element.
right : the right of the anchor element.
bottom : the bottom of the anchor element.
left : the left of the anchor element.
start : the logical start of the anchor element's "containing block" along the axis of the "inset" property on which the anchor() function is set.
end: the logical end of the anchor element's "containing block" along the axis of the "inset" property on which the anchor() function is set.
self-start : the logical start of the anchor element's "content" along the axis of the inset property on which the anchor() function is set.
self-end : thee logical end of the anchor element's "content" along the axis of the inset property on which the anchor() function is set.
center : the center of the axis of the "inset" property on which the anchor() function is set.
<percentage> : specifies the distance, as a percentage, from the start of the element's "content" along the axis of the "inset" property on which the anchor() function is set.
<length-percentage> : optional. Specifies a fallback value the function should resolve to if the anchor() function would otherwise not be valid.

The CSS anchor positioning module specifies two additional <anchor-side> values, "inside" and "outside", which have not yet been implemented.

anchor-size() : enables setting anchor-positioned element's size, position, and margins relative to the dimensions of anchor elements. It returns the <length> of a specified side of the target anchor element. anchor-size() is only valid when used within the value of anchor-positioned elements' "sizing", "inset", and "margin" properties.

this is an experimental technology

syntax : anchor-size(<anchor-name> <anchor-size>, <length-percentage>)

        /* sizing relative to anchor side */
        width: anchor-size(width);
        block-size: anchor-size(block);
        height: calc(anchor-size(self-inline) + 2em);

        /* sizing relative to named anchor's side */
        width: anchor-size(--myAnchor width);
        block-size: anchor-size(--myAnchor block);

        /* sizing relative to named anchor's side with fallback */
        width: anchor-size(--myAnchor width, 50%);
        block-size: anchor-size(--myAnchor block, 200px);

        /* positioning relative to anchor side */
        left: anchor-size(width);
        inset-inline-end: anchor-size(--myAnchor height, 100px);

        /* setting margin relative to anchor side */
        margin-left: calc(anchor-size(width) / 4);
        margin-block-start: anchor-size(--myAnchor self-block, 20px);
    

Parameters:

<anchor-name> : optional. The "anchor-name property value" of an anchor element you want to position the element's size, position, margins relative to. This is a <dashed-ident> value. If omitted, the element's default anchor is used.

<anchor-size> : pecifies the dimension of the anchor element that the positioned element's property values will be set relative to. Valid values include:

width : the width of the anchor element.
height : the height of the anchor element.
block : the length of the anchor element's containing block in the block direction.
inline : the length of the anchor element's containing block in the inline direction.
self-block : the length of the anchor element in the block direction.
self-inline : the length of the anchor element in the inline direction.
<length-percentage> : optional. Specifies the size to use as a fallback value if the element is not absolutely or fixed positioned, or the anchor element doesn't exist. If this parameter is omitted in a case when the fallback would otherwise be used, the declaration is invalid.

data types and values

anchor-center : aligns a positioned element with the center of its default anchor.

<anchor-side> : specifies the side of the anchor, or the relative distance from the start side, which the element is positioned relative to. If a physical or logical value is used that is not compatible with the inset property on which anchor() is set, the fallback value is used.

<anchor-size> : specifies the dimension of the anchor element that the positioned element's property values will be set relative to.

<position-area> : defines the cell or spanned cells of a position-area grid, a 3x3 grid whose center cell is an anchor element

<try-size> : defines the different try size fallback options, which specify criteria that determine what try fallback should be applied to the anchor-positioned element when it initially renders.

<try-tactic> : predefined fallback options move the positioned element by taking its computed position and transforming it across a particular axis of the anchor, mirroring any margin offsets


how to get rid of a floating footer?

top

When creatinga static web page, you may often find your footer floating up. To get rid of this problem and keep the footer at the bottom of the webapge, there are different ways possible:

1 - use "footer{position: fixed}" or "footer{position:sticky}"

example: footer position properties

            <style>
                /* (A) FOOTER */
                #page-footer {/* (A1) FIXED AT BOTTOM */ position: fixed; bottom: 0; left: 0; /* (A2) DIMENSIONS */ width: 100%; height: 40px; padding: 0 5px; /* (A3) CENTER TEXT */
                display: flex; align-items: center; justify-content: center; }
                /* (B) MAIN CONTENTS */
                #page-main {padding-bottom: 50px; /* SAME OR MORE HEIGHT THAN FOOTER */}
            </style>
            <header id="page-head">MY SITE</header>
            <main id="page-main">Last Line.</main>
            <footer id="page-footer">Copyright My Site</footer>
        

2 - use negative bottom margins on the element above the footer.

example: negative bottom margins

        <body>
            <div class="wrapper">content
                    <div class="push"></div>
            </div>
            <footer class="footer"></footer>
        </body>
        <style>
            html, body {height: 100%;}
            .wrapper { min-height: 100%;
                /* Equal to height of footer */
                /* But also accounting for potential margin-bottom of last child */
                margin-bottom: -50px;}
            .footer, .push { height: 50px;}
        </style>
        

3 - use negative top margins on the footer.

example: negative top margins

            <body>
                <div class="content">
                <div class="content-inside">content </div>
                </div>
                <footer class="footer"></footer>
            </body>
            <style>
                html, body {height: 100%; margin: 0;}
                .content {min-height: 100%;}
                .content-inside {padding: 20px; padding-bottom: 50px;}
                .footer {height: 50px; margin-top: -50px;
            </style>
        

4 - Use calc() to adjust the height of the element above the footer.

example: use calc() function

            <body>
                <div class="content">content</div>
                <footer class="footer"></footer>
            </body>
            <style>
                .content {min-height: calc(100vh - 70px);}
                .footer {height: 50px;}
            </style>
        

5 - use a flexbox layout that "stretches" the body section

example:

            <style>
                /* (A) FULL HEIGHT DOCUMENT */
                html, body {padding: 0; margin: 0; height: 100%; }
                /* (B) FLEXIBLE BOX ON BODY */
                body {display: flex; flex-direction: column;}
                /* (C) ALLOW MAIN CONTENT SECTION TO AUTO-FILL HEIGHT */
                #page-main { flex-grow: 1; }
            </style>
            <header id="page-head">MY SITE</header>
            <main id="page-main">Main contents</main>
            <footer id="page-footer">Copyright My Site</footer>
        

example: use calc() function

        <body>
            <div class="content">content</div>
            <footer class="footer"></footer>
        </body>
        <style>
            html, body {height: 100%;}
            body {display: flex; flex-direction: column;}
            .content {flex: 1 0 auto;}
            .footer {flex-shrink: 0;}
        </style>
        

6 - use a grid layout to achieve the "stretch body section"

example: use grid layout

            <style>
                /* (A) FULL HEIGHT DOCUMENT */
                html, body {padding: 0; margin: 0; height: 100%; }
                /* (B) GRID LAYOUT - AUTO-FILL HEIGHT FOR MAIN SECTION */
                body { display: grid; grid-template-rows: auto 1fr auto;}
            </style>
            <header id="page-head">MY SITE</header>
            <main id="page-main">Main contents</main>
            <footer id="page-footer">Copyright My Site</footer>
        

example: use grid layout

        <body>
            <div class="content">content</div>
            <footer class="footer"></footer>
        </body>
        <style>
                html {height: 100%;}
                body {min-height: 100%;display: grid; grid-template-rows: 1fr auto;}
                .footer {grid-row-start: 2; grid-row-end: 3;}
        </style>