Layout & Page Structure
Page Structure
- ICL Version 3+ (Astro)
- ICL Version < 3 (Pattern Lab)
The overall page structure is controlled by src/layouts/Layout.astro
. Astro uses slots to inject content from components or files.
Here is the structure (starting out at the <main id="main-content">
portion (this Layout file contains <head>
and <body>
tags which are irrelevant for this topic). The slots are all highlighted below. They can be named to target specific components (ie the subnav). New slots can be added as needed per project.
Note: This template contains logic to determine if this is the "homepage" or a component page, (the ICL Components/Page list) in order to alter the output on this page. The pages without the ICL Component/Page list contain the <div class="outer-pad">
wrapper.
<main id="main-content">
<slot name="hero" />
// Show outer-pad if not main index or a component page
{Astro.url.pathname !== '/' && !Astro.url.pathname.startsWith('/components') ? (
<div class="outer-pad">
<slot name="subnav" />
<div class="page-content">
<slot />
</div>
</div>
) : (
<>
<slot name="subnav" />
<div class="page-content">
<slot />
</div>
</>
)}
<slot name="end-of-page-cta" />
// Show site footer if not main index or a component page
{Astro.url.pathname !== '/' && !Astro.url.pathname.startsWith('/components') && <SiteFooter />}
</main>
Usage with Individual Page Templates
Pages will need to import the main layout in the frontmatter:
---
import Layout from '../layouts/Layout.astro';
// rest of frontmatter
A named slot can be used (subnav example) as:
<Subnav slot="subnav" subnav={data.ks_subnav.subnav} />
The rest of the components on the page using this template wihtout a slot will be inserted into the unnamed slot on the Layout.astro
page
The overall page structure is controlled by source/_patterns/pages/page-structure.twig
:
<div class="off-canvas">
<div class="max-bound">
{% include "@components/emergency-alert/emergency-alert.twig" %} {% include
"@components/site-header/site-header.twig" %}
<main id="main-content">
{% block hero %} {% endblock %}
<div class="outer-pad">
{% block subnav %} {% endblock %}
<div class="page-content">{% block content %} {% endblock %}</div>
</div>
{% block end_of_page_call_to_action %} {% endblock %} {% include
"@components/site-footer/site-footer.twig" %}
</main>
</div>
</div>
Usage with Individual Page Templates
Pages will then follow this pattern:
{% extends "@pages/page-structure.twig" %} {% block hero %}
<!-- Include Hero -->
{% endblock %} {% block subnav %}
<!-- Include Subnav (if needed, if not - leave blank) -->
{% endblock %} {% block content %}
<!-- Page Content -->
{% endblock %} {% block end_of_page_call_to_action %}
<!-- Include End Of Page Call To Action (if needed, if not - leave blank) -->
{% endblock %}
Modifying Page Structure
New blocks can be added as needed to insert different elements per page. For example if a unique site-header and site-footer were needed, page-structure.twig
could be modified to
<div class="off-canvas">
<div class="max-bound">
{% include "@components/emergency-alert/emergency-alert.twig" %} {% block
header %}{% endblock %}
<main id="main-content">
{% block hero %} {% endblock %}
<div class="outer-pad">
{% block subnav %} {% endblock %}
<div class="page-content">{% block content %} {% endblock %}</div>
</div>
{% block end_of_page_call_to_action %} {% endblock %} {% block footer %}{%
endblock %}
</main>
</div>
</div>
Usage in the page in this example:
{% extends "@pages/page-structure.twig" %} {% block header %}
<!-- Include Header -->
{% endblock %} {% block hero %}
<!-- Include Hero -->
{% endblock %} {% block subnav %}
<!-- Include Subnav (if needed, if not - leave blank) -->
{% endblock %} {% block content %}
<!-- Page Content -->
{% endblock %} {% block end_of_page_call_to_action %}
<!-- Include End Of Page Call To Action (if needed, if not - leave blank) -->
{% endblock %} {% block footer %}
<!-- Include Footer -->
{% endblock %}
Outer Padding
Inline (Left & Right) Padding
<div class="outer-pad">
is a direct descendent of the <main>
tag and is used to match the left and right spacing seen in the design reference (differs per project). The value will typically change according to screen-width and could also change per page template-type.
The inline padding (left and right) custom property values --outer-padding
can be updated in base.scss
. The value is changed based on screen width with media queries. One or two values can be used, if two values are used, the first is left padding and the second is right padding. For example:
// outer padding mobile
--outer-padding: 30px;
// outer padding tablet
@media (--tablet) {
--outer-padding: 60px;
}
// outer padding desktop
@media (--lg_desktop) {
--outer-padding: 100px;
}
- ICL Version 3+ (Astro)
- ICL Version < 3 (Pattern Lab)
Outer-pad is in the helpers.css file so that it can be re-used with @extend
(ie @extend .outer-pad;
):
.outer-pad {
padding-inline: var(--outer-padding);
&:has(.subnav) {
@media (--lg_desktop) {
display: grid;
grid-template-columns: var(--outer-pad-subnav-grid-width) minmax(0, 1fr);
gap: var(--outer-pad-subnav-grid-gap);
align-items: start;
}
}
}
<div class="outer-pad">
is a direct descendent of the <main>
tag and is used to match the left and right spacing seen in the design reference (differs per project). The value will typically change according to screen-width and could also change per page template-type.
The inline padding (left and right) custom property values --outer-padding
can be updated in base.scss
. The value is changed based on screen width with media queries. One or two values can be used, if two values are used, the first is left padding and the second is right padding. For example:
// outer padding mobile
--outer-padding: #{rem(30)};
// outer padding tablet
@include mq($min, $tablet) {
--outer-padding: #{rem(60)};
}
// outer padding desktop
@include mq($min, $lg_desktop) {
--outer-padding: #{rem(100)};
}
Outer-pad is a placeholder selector (so that it can be re-used) and is applied in placeholders.scss:
%outer-pad {
padding-inline: var(--outer-padding);
&:has(.subnav) {
@include mq($min, $lg_desktop) {
display: grid;
grid-template-columns: var(--outer-pad-subnav-grid-width) minmax(0, 1fr);
gap: var(--outer-pad-subnav-grid-gap);
align-items: start;
}
}
}
It's applied to .outer-pad
in layout.scss:
.outer-pad {
@extend %outer-pad;
}
Handling Outer Padding With a Subnav
When a page (ie the Kitchen Sink With Subnav variation) has a subnav, .outer-padding
class sets grid layout on desktop with the subnav as the first column and the main content <div class="page-content">
as the second column:
.outer-pad {
&:has(.subnav) {
@media (--lg_desktop) {
display: grid;
grid-template-columns: var(--outer-pad-subnav-grid-width) minmax(0, 1fr);
gap: var(--outer-pad-subnav-grid-gap);
align-items: start;
}
}
The custom properties used here --outer-pad-subnav-grid-gap
and --outer-pad-subnav-grid-width
are used in the formula to negate outer padding for full width components (see next section)
Negating Outer Padding for Full Width Components
Sometimes it's necessary to have a component take up the full width of the page - the helper class .negate-outer-pad-x
can be used to accomplish this.
.negate-outer-pad-x {
margin-inline: calc(var(--outer-padding) * -1);
body:has(.subnav) & {
@media (--lg_desktop) {
margin-inline: calc(
(
var(--outer-pad-subnav-grid-gap) + var(--outer-padding) +
var(--outer-pad-subnav-grid-width)
) * -1
)
calc(var(--outer-padding) * -1);
}
}
}
Padding-Top for the <main>
Element
The <main>
tag needs padding-top
set to push itself down underneath the site header. Custom propties used with the site header help to create a formula to achieve this without the need for editing (in most cases):
main {
padding-top: var(--header-top-height);
@media (--lg_desktop) {
padding-top: calc(
var(--header-top-height) + var(--header-main-menu-height)
);
}
body:has(.site-header--hamburger) & {
@media (--lg_desktop) {
padding-top: var(--header-top-height);
}
}
}
Spacing Between Kitchen Sink Components
Spacing between kitchen sink components is managed by adding a wrapper to each component on the page level (wrapper classes are not added in the component file - but in the page where they are included).
- The wrapper class will be
paragraph-widget
as well as the sameparagraph-widget-component-name
to give extra specificity if certain components need different spacing. For example, to wrap thebutton-set
component - this is how it would appear on a page (for example on the kitchen sink):
<div class="paragraph-widget paragraph-widget--button-set">
{% include "@components/buttons-links/button-set.twig" with
kitchen_sink_button_set %}
</div>
The general paragraph widget spacing css is handled in base.css
and will need updated per project, according to the design.
- Use
margin-bottom
for the spacing to avoid margin collapsing - If a particular component needs different spacing, handle this in the respective component's scss file using the unique paragraph widget class (ie
paragraph-widget--button-set
), ideally at the start of the file. For example in the button set:
.paragraph-widget--button-set {
margin-bottom: 10px;
}
.button-set {
// rest of styles
Testing Space Between Components
- When the site is integrated and actual real-world content entered, the ordering of components will vary greatly
- It can be beneficial to re-order kitchen sink components temporarily on a page to ensure that there are no unwanted spacing issues that will occur
- This can be done by either re-ordering in the respective page's twig file, or by using dev tools to move sections
Site Width
There is no max-width
set on the site. Instead, since rem units are used throughout (PostCSS converts pixel values to rems on dev/build) - we can increase the size (essentially scale) the site at larger viewport widths. In base.css
the html
element has the following style applied at the max_desktop
width:
html {
// other styles not relevant to site width not displayed here for clarity
@media (--max_desktop) {
font-size: calc(100% + 0.2vw);
}
}
Updating the font size with a small vw
unit here will dynamically increase the value of rems throughout the site, giving the scaling effect.