prygara.com – html, css, javascript, testing

project-001

About project-001

Layout

This site was built using WordPress Underscores theme. We have the following HTML structure produced by header.php, page.php and footer.php.

HTML

<div id="page" class="site"> 
<header class="site-header"> ...  </header>   
<main class="site-main"> ... </main> 
<footer  class="site-footer"> ... </footer>  
</div>

The site uses CSS grid for layout. I used div class="site" as main container for the grid. I wanted to have a sticky footer layout so I used one of the methods described here.

CSS

.site {
  display: grid;
  min-height: 100vh;
  grid-template-columns: repeat(3, 1fr);
}

As you can see in the above CSS declaration block there’s min-height: 100vh – it stretches the div within body element. We also declare 3 grid columns of 1 fr each meaning they would accomodate the content within them and become as wide as their content.

Header and navigation

Header has the following HTML structure produced by header.php

HTML

<header id="masthead" class="site-header">
<div class="site-branding">...</div>
<nav id="site-navigation" class="main-navigation">...</nav>
</header>

CSS

.site-header {
grid-column: 1/-1;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
...
}

Our header is a grid item as it is a direct child of a div .site which is our grid container. As you can see in the above CSS declaration block I used grid-column: 1/-1; to stretch the header across all 3 grid columns (negative value -1 automatically stretches it to the last grid line of a 3rd column). At the same time we declare our header as a flex container by display: flex;. Our div .site-branding and nav .main-navigation are now flex items aligned accordingly by justify-content and align-items. We also allow things to wrap using flex-wrap: wrap; when there’s not enough space.

Top navigation markup is produced by the following mix of HTML and PHP in header.php.

HTML,PHP

<nav id="site-navigation" class="main-navigation">
  <input id="menu-toggle" type="checkbox" />
  <label onclick="myFunction()" class='menu-button-container' for="menu-toggle">
      <span class='menu-button'></span>
    </label>
    <?php
      wp_nav_menu (
        array (
          'theme_location' => 'menu-1',
          'menu_id'        => 'primary-menu',
          'container'      => false 
          )
      );
   ?>
</nav><!-- #site-navigation -->

Here’s the HTML output for the above mix of HTML and PHP code.

HTML

<nav id="site-navigation" class="main-navigation">
  <input id="menu-toggle" type="checkbox">
  <label onclick="myFunction()" class="menu-button-container" for="menu-toggle">
             <span class="menu-button"></span>
  </label>
       <ul id="primary-menu" class="menu">
            <li>About</a></li>
            <li>Work</a></li>
            <li>Services</a></li>
           <li>Contact</a></li>
       </ul>
</nav>

Navigation – desktop view

We make .main-navigation a flex container with 3 direct children: input, label and ul. We give our .menu a width of 35rem and make it a flex container so we can control our list items (direct children) with justify-content and align-items.

CSS

.main-navigation {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.menu {
  width: 35rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  list-style-type: none;
  ...
}

Navigation – mobile view

I tried to accomodate the idea of the following menu. It is based on the old “Checkbox Hack” method where input and label are connected via ID attribute. As per MDN “To explicitly associate a label element with an input element, you first need to add the id attribute to the input element. Next, you add the for attribute to the label element, where the value of for is the same as the id in the input element.”

In our case we use # menu-toggle in the input element and hide it with display: none; so checkbox is not visible. Our input and label elements are now connected via ID menu-toggle. Even though the checkbox is hidden, clicking it still toggles its value on and off. We use it to further style our menu using general sibling combinator #menu-toggle:checked ~ and adjacent sibling combinator #menu-toggle:checked +.

CSS

#menu-toggle {
display: none;
}

Next we make our label a container for the hamburger. At this point its content is hidden with display: none;

.menu-button-container {
    display: none;
    height: 20%; 
    width: 45px;
    cursor: pointer;
}

In the original HTML the menu author nested HTML div element within label element.

<label class='menu-button-container' for="menu-toggle">
   <div class='menu-button'></div>
</label>

As we know we can’t nest block level div within inline level label so we replace div with a span in HTML.

<label class='menu-button-container' for="menu-toggle">
   <span class='menu-button'></span>
</label>

Now we have valid HTML since both label and span are inline level elements.

The following CSS declaration blocks are used to create the hamburger icon containing gold, green and red lines. Our absolutely positioned .menu-button becomes a flex item of a parent .menu-button-container. Chris Coyier provides two examples of absolutely positioned flex items. Interestingly enough bottom: 20px; for the absolutely positioned child trumps align-self: center; in this example.

Also by adding position: absolute; to a span .menu-button span display value changes from default display: inline to display: block. Important to note that it doesn’t change what kind of element span is – it still remains an inline element in HTML.

.menu-button,
.menu-button::before,
.menu-button::after {
  display:block;
  background-color: gold;
  position: absolute;
  height: 7px;
  width: 45px;
  transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
  border-radius: 2px;
}

We use ::before and ::after pseudo-elements to generate two additional lines for the hamburger. Interesting discussion can be found here as to why ::before and ::after pseudo-elements require empty content: ''; We then use margin-top: -10px; and margin-top: 10px; to place green and red stripes on top and below yellow one.

.menu-button::before {
  content: '';
  margin-top: -10px;
  background-color: green;
}

.menu-button::after {
  content: '';
  margin-top: 10px;
  background-color: red;
}

Since our input and label are connected via # menu-toggle we use input :checked state to rotate green and red stripes. We also hide yellow stripe with background: transparent;

CSS

#menu-toggle:checked + .menu-button-container .menu-button::before {
  margin-top: 0px;
  transform: rotate(400deg);
}

#menu-toggle:checked + .menu-button-container .menu-button {
  background: transparent;
}

#menu-toggle:checked + .menu-button-container .menu-button::after {
  margin-top: 0px;
  transform: rotate(-400deg);
}

At max-width: 1450px media query our .site-header changes its default flex-direction: row; to flex-direction: column;

@media (max-width: 1450px) {
  .site-header {
    flex-direction: column;
    text-align: center;
  }

Next at @media (max-width: 570px) media query we introduce the following changes. All the CSS declarations below except JavaScript function and before next paragraph about site footer are included into @media (max-width: 570px) media query.

We flip our header back to flex-direction: row; so that its 2 children .site-title and .main-navigation are positioned horizontally along the main axis. Position relative on .site-header allows to absolutely position .menu right below the header and keep it there.

CSS

.site-header {
  flex-direction: row;
  position: relative;
  flex-wrap: nowrap;
  column-gap: 1rem;
  text-align: left;
  padding: 1.5rem 0;
}

.menu {
  position: absolute;
  top: 100%;
  left: 0;
  flex-direction: column;
  width: 100%;
  display: none;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

We hide (remove) our .site-description with display: none; allowing other elements occupy their place in the page flow if needed.

.site-description {
  display: none;
}

We hide our navigation…

.menu {
  ...
  display: none;	
  ...
}

…and then show it by adding a new class .topnav with JavaScript on click.

JavaScript

function myFunction() {
  var element = document.getElementById("primary-menu");
  element.classList.toggle("topnav");
}

New class .topnav flips .menu back to visible state.

.topnav {
  display: flex;
}

Our hamburger .menu-button sits within .menu-button-container and was previously hidden.

CSS

.menu-button-container {
  display: none;
  height: 20%;
  width: 45px;
  cursor: pointer;
}

Now we make it visible.

.menu-button-container {
  display: flex;
}

We make each list item a flex container and center our menu items horisontally and vertically.

CSS

.menu > li {
  display: flex;
  justify-content: center;
  align-items: center;
  ...
}

We also use :checked state of our checkbox to transition the height of menu items.

CSS

#menu-toggle ~ .menu li {
  height: 0;
  ...
  border: 0;
  transition: height 400ms cubic-bezier(0.23, 1, 0.32, 1);
}

#menu-toggle:checked ~ .menu li {
  border: 1px solid #333;
  height: 4.5rem;
  transition: height 400ms cubic-bezier(0.23, 1, 0.32, 1);
}

Footer


Footer HTML structure is produced by footer.php (see the following PHP code that sits within footer.php). I registered 3 sidebars in functions.php and then called them in footer.php using dynamic_sidebar function and their IDs. Sidebars contain nav, categories and social icons.

PHP

<?php? >
<footer id="colophon" class="site-footer"> 
   <?php dynamic_sidebar('footer-1');?>
   <?php dynamic_sidebar('footer-2');?>
   <?php dynamic_sidebar('footer-3');?>
<?php wp_footer(); ?>

Here’s HTML structure produced by footer.php. I removed some WordPress CSS class names for the sake of brevity. Here’s a good read on default WordPress CSS classes and IDs.

HTML

<footer class="site-footer>
    <div class="widget widget_block">
      <ul class="wp-block-page-list">
        <li><a href="">About</a></li>
        <li><a href="">Work</a></li>
        <li><a href="">Services</a></li>
        <li><a href="">Contact</a></li>
      </ul>
    </div>

    <div class=" widget_categories">
      <ul class="wp-block-categories-list">
       <li><a href="">Demos</a></li>
       <li><a href="">Digital</a></li>
       <li><a href="">Sound</a></li>
       <li><a href="">Vocal</a></li>
      </ul>
    </div>

     <div class="widget widget_block">
       <ul class="wp-block-social-links ">
        <li><a href="">Facebook</a></li>
        <li><a href="">Instagram</a></li>
        <li><a href="">Vimeo</a></li>
        <li><a href="">Youtube</a></li>
       </ul>
     </div> 
</footer>

Site footer is contained within a grid. It has 3 columns and stretches to last column line by using grid-column: 1/-1;

CSS

.site-footer {
  display: grid;
  grid-column: 1/-1;
  grid-template-columns:1fr 1fr 1fr;
  padding: 1.5rem 0;
}

There are 3 child divs within the footer. We select those by using CSS child selector combined with unversal selector and make them flexboxes.

.site-footer > *{
  display: flex;
  text-transform: uppercase;
}

Next we target our 3 unordered lists and align list items vertically on the cross-axis.

.wp-block-page-list,
.wp-block-categories-list,
.wp-block-social-links {
  display: flex;
  align-items: flex-start;
  width: auto;
 ...
}

At 1450px screen width we make our footer flex and then at 1000px wrap our flex items – 3 divs.

CSS

@media screen and (max-width: 1450px) {
  .site-footer {
    display: flex;
    justify-content: space-between;
    }  
  }
@media screen and (max-width: 1000px) {
  .site-footer {
    flex-wrap: wrap;
    justify-content: space-around;
    column-gap: 2.5rem;
    row-gap: 1.2rem;
  }
}

At 800px screen width we change flex-direction to column. Our main-axis now runs vertically and cross axis horizontally. We center our flex items on the cross axis.

@media screen and (max-width: 800px) {
  .site-footer {
    flex-direction: column;
    align-items: center;
   }
}

About page

This page is generated by page.php and content-page.php templates. It is set to Homepage in the dashboard Settings -> Reading.

HTML,PHP

page.php

<?php get_header();?>
    <main id="primary" class="site-main">
     <?php
         while ( have_posts() ) :
         the_post();
         get_template_part( 'template-parts/content', 'page' );
         endwhile; // End of the loop.
        ?>
     </main>
    <?php
get_footer();

content-page.php

<?php?>
<header class="entry-header">
   <?php the_title( '<h1 class="entry-title">', '</h1>' );?>
</header><!-- .entry-header -->
   <?php post_thumbnail();?>
<section class="entry-content">
   <?php  the_content();?>
</section>

About page layout problem

I came across one issue when working on About page – text in the column next to the image wouldn’t wrap on smaller screens.


My HTML was as following.

<div class="entry-content">
<figure class="wp-block-image"><img.../></figure>
<div>...</div>
<div>...</div>
</div>

Say if .entry-content is a flex container in the above HTML, we have 3 flex children: figure and two divs. We can’t float: left; our figure containing an image so that text from the next div wraps under the image because…

https://www.w3.org/TR/css-flexbox-1/#flex-containers

“Flex containers are not block containers, and so some properties that were designed with the assumption of block layout don’t apply in the context of flex layout. In particular: float and clear do not create floating or clearance of flex item, and do not take it out-of-flow.”

About page layout solution

At Sitepoint forums I was guided in the right direction – wrap HTML figure element and the next div in a separate div. So this way they are no longer direct children of a flexbox and we can float our figure image. Now we have 2 container divs: .inner-1 and .inner-2.

HTML

<div class="entry-content">
  <div class="inner-1">
     <figure class="wp-block-image"><img.../></figure>
     <div>...</div>
  </div>
  <div class="inner-2">...</div>
</div>

CSS is pretty much self-explanatory.

CSS

.home .entry-content {
  display: flex;
  font-size: 1.3rem;
  column-gap: 1rem;
  max-width: 1680px;
  margin: auto;
}
.home .inner-1 { 
  flex: 1.5 0 0;
  ...
}
.home .inner-1 figure {
  float: left;
  ...
}

Work page

This is a blog page generated by index.php and content.php. It is set to Posts page in the dashboard Settings -> Reading.

index.php

HTML,PHP

<?php get_header();?>
<main id="primary" class="site-main">
<?php
   if ( have_posts() ) :
   if ( is_home() && ! is_front_page() ) :
?>
   <header>
   <h1 class="page-title"><?php single_post_title(); ?></h1>
   </header>
</header><!-- .entry-header -->
   <section>
   <!-- Begin Sendinblue Form -->
   <div class="sib-form">
   ...
   </div>
<script defer src="https://sibforms.com/forms/end-form/build/main.js"></script>
<?php
   endif;
/* Start the Loop */
   while ( have_posts() ) :
   the_post();
      get_template_part( 'template-parts/content', get_post_type() );
   endwhile;
   the_posts_navigation();
   else :
      get_template_part( 'template-parts/content', 'none' );
   endif;
?>
   </section>
</main><!-- #main -->
<?php
get_footer();

content.php

<?php?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
   <header class="entry-header">
     <?php
       if ( is_singular() ) :
       the_title( '<h1 class="entry-title">', '</h1>' );
       else :
       the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
       endif;
       if ( 'post' === get_post_type() ) :
     ?>
     <?php endif; ?> 
   </header>
   <div class="entry-content">
      <div class="entry-meta"><?php..._posted_on(); ..._posted_by();?></div><!-- .entry-meta -->
      <?php the_excerpt();?>
   <div class="read-more">
   <?php 
     $read_more_link = sprintf(
     wp_kses(
    /* translators: %s: Name of current post. Only visible to screen readers */
    __( 'Read more &raquo; <span class="screen-reader-text"> "%s"</span>', '...' ),
       array(
       'span' => array(
       'class' => array(),
        ),
            )
       ),
       wp_kses_post( get_the_title() )
    );?>
    <a href="<?php echo esc_url( get_permalink() ) ?>" rel="bookmark">
        <?php echo $read_more_link; ?>
    </a>
</div>
</div><!-- .entry-content -->
</article><!-- #post-<?php the_ID(); ?> -->

HTML

Subscription form and blog posts (videos with text excerpts) are contained within section. Blog posts sit within article so each article is a blog post.

<main>
<section>
<div class="sib-form">
  <div id="sib-form-container">...</div>
<script defer="" src="https://sibforms.com/forms/end-form/build/main.js"></script>
<article >
  <header class="entry-header">
    <h2 class="entry-title"><a href="">Post title</a></h2>
  </header>
<div class="entry-content">
  <div class="entry-meta">
    <span class="posted-on">Posted on <a href="" ><time >...</time></a></span>
    <span class="byline">by<span class="author vcard"><a href="">...</a></span></span>
  </div><!-- .entry-meta -->
  <figure class="wp-block-embed is-type-video ">
    <iframe loading="lazy" title="..." width="854" height="480" src="..."></iframe>
  </figure>
  <p>…</p>
  <div class="read-more">
    <a href="">Read more » <span class="screen-reader-text">...</span> </a>
  </div>
</div><!-- .entry-content -->
</article>
</section>
</main><!-- #main -->

Work page – problem with subscription form layout

As you can see in the above HTML, subscription form class="sib-form" is placed within section which is a grid with 2 columns (see CSS declaration block below).

CSS

.blog .site-main section {
  display: grid;
  grid-template-columns: 2fr 2fr;
  ...
 }

In such scenario the form becomes a grid item and sits within a grid cell followed by another grid cell (see the following screenshot).

I needed the form to stretch across the page.We can stretch the form by using grid-column shorthand with negative value. In the following example the form would start at line 1 and end up at last line of the column.

.sib-form[style] {
  grid-column: 1/-1;
  ...
}

Work page – problem with Youtube videos layout

WordPress uses embeds where you can paste Youtube video URL to display video on a page. That is how I displayed Youtube videos on Work page. My original video aspect ratio is 16:9, frame width: 640, frame height 360. I wanted to make videos a little bit bigger so they take more of white space on work page. I checked the next resolution within 16:9 aspectio ratio was 854 x 480. It appears there are two approaches that worked for me.

Approach 1

I used the following WordPress function in function.php to change videos to 854 x 480.

function.php

 function mycustom_embed_defaults($embed_size){
    $embed_size['width'] = 854;
    $embed_size['height'] = 480;
    return $embed_size;
    }
 add_filter('embed_defaults', 'mycustom_embed_defaults');

CSS

.blog article {
   max-width: 854px;
   margin: 0 auto;
   ...
 }

Approach 2

At Sitepoint forums I was refered to Fluid Width Video techniques. As mentioned in that CSS Tricks article Youtube videos wrapped in iframe are squeezed to 150px height.

“Literally all browsers will render iframe, canvas, embed, and object tags as 300px × 150px if not otherwise declared. Even if this isn’t present in the UA stylesheet.”

and that was exactly what happened when I tried this

.wp-block-embed iframe {
    max-width: 854px;
    width:100%;
    height:auto;
  }

All my embedded Youtube videos wrapped in iframe got squeezed to 150px height.


At Sitepoint I was guided in the right direction. I haven’t used aspect-ratio CSS property before. This is also discussed in the last comment in the Fluid Width Video techniques CSS Tricks article.

.wp-block-embed iframe {
    width:100% !important;
    height:auto !important;
    aspect-ratio: 16 / 9;
}

 .blog article  {
    max-width: 854px;
    margin: 0 auto;
    font-size: 1.2rem;
}

The above two CSS declarations solved the iframe videos problem for me.

Single post view page

Single post view page is generated by single.php, content-single.php and sidebar.php.

single.php

<?php get_header();?>
  <main id="primary" class="site-main">
  <h1 class="page-title">
      <?php echo get_the_title( get_option('page_for_posts', true) ); ?>
  </h1>
  <section>
     <?php while ( have_posts() ) :
      the_post();
      get_template_part( 'template-parts/content', 'single');
      endwhile; //End of the loop
      ?>
  </section>
  </main>
<?php
get_footer();

content-single.php

<?php?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<?php
if ( is_singular() ) :
   the_title( '<h1 class="entry-title">', '</h1>' );
else :
   the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
endif;
if ( 'post' === get_post_type() ) :
?>
<?php endif; ?> 
</header>
<?php post_thumbnail(); ?>
<section class="entry-content">
<div class="entry-meta"><?php posted_on(); posted_by();?></div>
<?php the_content();?>
</section><!-- .entry-content -->
<?php get_sidebar();?>
<?php the_post_navigation(
array(
'prev_text' => '<span class="nav-subtitle">' . esc_html__('Previous', '...').'</span> <span class="nav-title">%title</span>',
'next_text' => '<span class="nav-subtitle">' . esc_html__('Next', '...').'</span> 
<span class="nav-title">%title</span>',
)
);
?>
</article><!-- #post-<?php the_ID(); ?> -->

sidebar.php

<?php if ( ! is_active_sidebar( 'sidebar-1' ) ) {return;}?>
<aside id="primary" class="widget-area">
<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside><!-- #secondary -->

HTML output from single.php, content-single.php and sidebar.php.

<div id="page" class="site">
<header id="masthead" class="site-header">
<div class="site-branding">
   <p class="site-title">... </p>
   <p class="site-description">...</p>
</div><!-- .site-branding -->
<nav id="site-navigation" class="main-navigation">
</nav><!-- #site-navigation -->
</header><!-- #masthead -->
<main id="primary" class="site-main">
   <h1 class="page-title">Work</h1>
    <section>
      <article class="post type-post status-publish ategory-demos">
        <header class="entry-header"><h1 class="entry-title">...</h1></header>
      <section class="entry-content">
      <div class="entry-meta">
         <span class="posted-on">Posted on <a href=""><time >...</time></a></span>
         <span class="byline"> by <span ><a href="">...</a></span></span>
      </div><!-- .entry-meta -->
        <figure class="wp-block-embed is-type-video">
        <div class="wp-block-embed__wrapper">
        <iframe title="..." width="854" height="480" src="">...</iframe>
        </div>
        </figure>
        <p>... </p>
      </section><!-- .entry-content -->
<aside id="primary" class="widget-area">
<div class="widget_recent_entries">
<h2 class="widget-title">Recent Posts</h2>
    <ul>
      <li><a href="">...</a></li>
      <li><a href="">...</a></li>
     </ul>
</div>
<div class="widget_categories"><h2 class="widget-title">Categories</h2>
    <ul>
      <li><a href="">...</a></li>
      <li><a href="">...</a></li>
    </ul>
</div>
<div class="widget_block"><h2 class="widget-title">Post Tags</h2>
  <div>
   <p>
     <a href="">...</a>
     <a href="">...</a>
   <p>
  </div>
</div>
</aside><!-- #secondary -->
<nav class="post-navigation" aria-label="Posts">
   <div class="nav-links">
     <div class="nav-previous"><a href=""><span class="nav-subtitle">Previous</span> 
       <span class="nav-title">...</span></a>
     </div>
   </div>
</nav>
</article>
</section>
</main><!-- #main -->
<footer class="site-footer">...</footer> 
</div>

On a single post view page each article is a wrapper for a post header, post content section, sidebar aside and post navigation nav.

CSS

.single-post article {
 display: flex;
 flex-wrap: wrap;
 justify-content: space-between;
 max-width: 1050px;
 margin: 0 auto;
}

Post content section occupies 60% of the width and sidebar aside 30%. This way we can use justify-content: space-between; in the above declaration block as there’s still 10% available space.

.single-post .entry-content {
width: 60%;
}
.single-post aside {
width: 30%;
}

Single post view page – long post titles in post navigation in mobile view

Here’s our HTML for post navigation.

<div class="nav-links">
  <div class="nav-previous">
   <a href="" >
    <span class="nav-subtitle">Previous</span> 
    <span class="nav-title">Donec pellentesque commodo mauris non aliquet</span>
   </a>
  </div>
  <div class="nav-next">
   <a href="">
    <span class="nav-subtitle">Next</span> 
    <span class="nav-title">Nam ornare cursus dui, non tristique velit</span>
   </a>
  </div>
</div>

CSS

.single-post .nav-links {
  display: flex;
  justify-content: space-between;
  gap: 1rem
}

As you can see above we have a flex container .nav-links with two flex children: .nav-previous and .nav-next. Inside those we have two span elements containing the words “Previous” or “Next and the post titles. This is how it is set up for desktop view. In most cases the post titles within .nav-title would be of different length and there might be not enough space in mobile view for a long post title.


So how can we accomodate longer post titles on mobile view? First I removed colon symbols (:) from the_post_navigation function in content-single.php. As you can see those symbols come after ‘Previous’ and ‘Next ‘ words in esc_html__() function.

<?php
the_post_navigation(
 array(
 'prev_text' => '<span class="nav-subtitle">'. esc_html__( 'Previous :','') .'</span>     <span class="nav-title">%title</span>',
 'next_text' => '<span class="nav-subtitle">'. esc_html__( 'Next :','') .'</span>         <span class="nav-title">%title</span>'
   )
 );
?>

Then the following two media queries did the job.

CSS

@media screen and (max-width: 1000px) {

.single-post .nav-links {
   display: block;
   line-height: 1.5;
}

.single-post .nav-links a {
   display: grid;
}

.single-post .nav-subtitle {
   display: block;
}

.single-post .nav-next {
   text-align: right;
}

.single-post .nav-previous .nav-title,
.single-post .nav-next .nav-title {
   display: block;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
}

.single-post .nav-previous .nav-title {
   content: '';
   border-bottom: 2px solid grey;
}

.single-post .nav-previous .nav-subtitle::before {
   content: "\AB"; 
}

.single-post .nav-next .nav-subtitle::after {
   content: "\BB"; 
}

}

In the above media query we display: block our div with a class .nav-links which is a container for .nav-previous and .nav-next. This cancels previous display: flex for desktop view and makes the “Next” post title drop under “Previous”.

.nav-previous and .nav-next each contain HTML anchor elements which wrap two spans: one span .nav-subtitle containing the word “Previous” added with ::before pseudo element and another span .nav-title containing the post title itself. Same applies to .nav-next.

I came across this article about text-overflow: ellipsis not working. In one part of the article the author suggests using display: grid on a parent which in my case is an HTML anchor tag containing .nav-subtitle and .nav-title. So using .single-post .nav-links a display: grid; in the above media query made text-overflow: ellipsis work for me – without display: grid it wasn’t working. Rest of the above media query CSS is pretty much self-explanatory.

@media screen and (min-width: 1001px) {
.single-post .nav-previous .nav-subtitle::after {
 content: "\003A"; 
 margin-right: 0.5rem;
}
.single-post .nav-next .nav-subtitle::after {
 content: "\003A"; 
 margin-right: 0.5rem;
}
}

Since I previously removed colon symbols (:) from the_post_navigation function in content-single.php, I put those back on screens larger than 1000 px. The above media query does exactly just that.

Services page

Services page page is generated by page.php and content-page.php. See About page section for page.php and content-page.php code.

HTML

Following is the reduced version of HTML – try “ViewSource” if you want to see full HTML.

<section>
  <article>
    <h1></h1>
    <p>...</p>
  </article>
  <article>
   <h1></h1>
   <ul>
    <li>...</li>
   </ul>
  </article>
  ...
</section>

Services page – problem with borders alignment

I used WordPress block editor to insert content into Services page. The text options in the editor are mostly different levels of headings from h1 to h6 and p tags that automatically wrap around the text. As you can see “Why We Started! ” and “Course Outline” headings have colored borders. There are also colored borders below each portion of the text that follows the headings. I initially tried to use flexbox to layout content so that at different screen width colored borders on the left and right stay on the same level. It didn’t work.

Part of the problem was that headings and the text that follows them were incorrectly marked up in HTML. Folks at Sitepoint forum pointed me in the right direction. The solution was to wrap each heading and text in a separate div making it a separate block of content. It also turns out that the most suited tool for the job was CSS grid and not flexbox.

Here’s what I did. Instead of a div I structured the page content using HTML article elements (see above HTML or just View Source in your browser). There are eight article elements that sit within section. I decided to use article since I considered each part independent of each other with its own heading and text. Say “Why We Started! ” is not logically conected to “Performance and Recording” in my opinion.

CSS

.services .entry-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto;
  column-gap: 2.5rem;
  font-size: 1.3rem;
  position: relative; 
  max-width:1680px;
  margin:auto;
  border-top:none;
}

The above CSS declaration block lays out above mentioned eight article elements in two columns. There’s position: relative that keeps the vertical divider line (between left and right columns) within section.

.services .entry-content:after {
  content: "";
  position: absolute;
  width: 2px;
  top: 1rem;
  left: calc(50% - 1px);
  bottom: 1rem;
  background: gray;
}

The vertical divider was created using :after pseudo-element (see above declaration block). I knew about pseudo-elements, however, didn’t think about its use in this scenario. Folks at Sitepoint forums pointed me in the right direction. There’s also left offset with left: calc(50% - 1px) where we minus 1px to center a 2px divider properly between left and right columns.

Services page – keep the order of blocks using CSS order property

Since our eight article elements sit within section using display: grid, they are laid out left to right top to bottom with grid-template-rows: auto. If understand this correctly even if I didn’t use grid-template-rows: auto in the following CSS, items would still be laid out left to right top to bottom because of the CSS grid auto-placement algorithm.

.services .entry-content {
 display: grid;
 grid-template-columns: 1fr 1fr;
 grid-template-rows: auto;
 .... 
}

I wanted to change the default order to keep “Why We Started!”, “What Is Next On The Agenda?”, “What We Do For You” and “Services include” in the left column and “Course Outline” on the right. For that I used CSS order property.

.services article:nth-child(1){
  order: 1;
}

On screens 1080px width or less we remove order property, divider and just stack them in their order of appearance in HTML using grid-template-columns: 1fr.

@media screen and (max-width: 1080px) {
.services .entry-content {
 grid-template-columns: 1fr;
}
.services .entry-content > article {
 order: initial !important; /* override nth-child*/
 font-size: 1.2rem; 
}
.services .entry-content:after{
 display: none;
}
}

Contact page

Contact page is generated by page.php and content-page.php. For contact form I used Contact Form 7 plugin. I gave it max-width and centered it on the page.

.wpcf7 {
 max-width: 960px;
 margin: auto;
}

The form comes with its own CSS classes which I used to style it. To set it up on the backend I used instructions from contactform7.com and kinsta.com/blog/contact-form-7.