CSS – Build Cool Forms

Today, we are going to build a cool form using CSS. I am specifically going to use followings.

1. solid color gradients
2. sibling selectors
3. ::input-placeholder pseudo-element
4. :focus, :invalid, placeholder-shown, :checked pseudo classes

Please note that I have learned this from the udemy course by Jonas Schmedtmann.

Let’s take a look at the final result first

Form

There is a couple of things to note here.

  • Animation from placeholder to label to indicate the field
  • CSS created radio button
  • cool shape with background image

Let’s take a look at the code now

HTML Code

<section class="section-book">
    <div class="row">
        <div class="book">
            <div class="book__form">
                <form action="#" class="form">
                    <div class="u-margin-bottom-medium">
                        <h2 class="heading-secondary">
                            Start booking now
                        </h2>
                    </div>

                    <div class="form__group">
                        <input type="text" class="form__input" placeholder="Full name" id="name" required>
                        <label for="name" class="form__label">Full name</label>
                    </div>

                    <div class="form__group">
                        <input type="email" class="form__input" placeholder="Email address" id="email" required>
                        <label for="email" class="form__label">Email address</label>
                    </div>

                    <div class="form__group u-margin-bottom-medium">
                        <div class="form__radio-group">
                            <input type="radio" class="form__radio-input" id="small" name="size">
                            <label for="small" class="form__radio-label">
                                <span class="form__radio-button"></span>
                                Small tour group
                            </label>
                        </div>

                        <div class="form__radio-group">
                            <input type="radio" class="form__radio-input" id="large" name="size">
                            <label for="large" class="form__radio-label">
                                <span class="form__radio-button"></span>
                                Large tour group
                            </label>
                        </div>
                    </div>

                    <div class="form__group">
                        <button class="btn btn--green">Next step →</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</section>

There are multiple form groups under form to click the form when label is clicked. It is a typical html forms you can find.

CSS Code

This is the CSS code. Please note that I used SCSS and there are some variables for colors and font size which could be replaced with normal values you would like. I am going to explain each class separately for better understanding

section-book and book

.section-book {
  padding: 15rem 0;
  background-image: linear-gradient(to right bottom, $color-primary-light, $color-primary-dark);
}

.book {
  background-image: linear-gradient(105deg,
    rgba($color-white, .9) 0%, 
    rgba($color-white, .9) 50%,
    transparent 50%), 
    url(../img/nat-10.jpg);
  background-size: cover;
  // this is also possible
  // background-size: 100%; 

  border-radius: 3px;
  box-shadow: 0 1.5rem 4rem rgba($color-black, .2);

  height: 50rem;

  &__form {
    width: 50%;
    padding: 6rem;
  }
}

As you can see in the example, there is a trapezoid shape (form) on top of the background image. You could use clip-path to make the shape. But you could also use another properties of linear-gradient. In linear-gradient, you can specify color at each percentage. And as you see in the code, white color at 50% and transparent at 50% will actually make the shape because it’s gradient – white and transparent will be mixed at 50%.

Form classes

.form {
  &__group:not(:last-child) {
    margin-bottom: 2rem;
  }

  &__input {
    font-size: 1.5rem;
    font-family: inherit;
    color: inherit;
    padding: 1.5rem 2rem;
    border-radius: 2px;
    background-color: rgba($color-white, .5);
    border: none;
    border-bottom: 3px solid transparent;
    width: 90%;
    display: block;
    transition: all .3s;

    &:focus {
      outline: none;
      box-shadow: 0 1rem 2rem rgba($color-black, .1);
      border-bottom: 3px solid $color-primary;
    }

    &:focus:invalid {
      border-bottom: 3px solid $color-secondary-dark;
    }

    &::-webkit-input-placeholder {
      color: $color-gray-dark-2;    
    }
  }

  &__label {
    font-size: 1.2rem;
    font-weight: 700;
    margin-left: 2rem;
    margin-top: .7rem;
    display: block;
    transition: all .3s;
  }

  // select when placeholder is shown in the input
  // adjacent sibling selector (only if it's adjacent. no other elements in the between allowed
  // + adjacent (order matters), ~ general
  &__input:placeholder-shown + &__label{
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4rem);
  }

  &__radio-group {
    width: 49%;
    display: inline-block;
  }

  &__radio-input {
    display: none;
  }

  &__radio-label {
    font-size: $default_font-size;
    cursor: pointer;
    position: relative;
    padding-left: 4.5rem;
  }

  &__radio-button {
    height: 3rem;
    width: 3rem;
    border: 5px solid $color-primary;
    border-radius: 50%;
    display: inline-block;

    // position just need to be specified for child position absolute
    // it doesn't need to be relative
    position: absolute;
    left: 0;
    top: -.4;

    // content, display property is mandatory for all pseudo element    
    &::after {
      content: "";
      display: block;
      height: 1.3rem;
      width: 1.3rem;
      border-radius: 50%;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: $color-primary;
      opacity: 0;
      transition: opacity .2s;
    }
  }

  // as soon as selected, radio input checked will be on. then this selector will be enabled
  // radio-label (sibling) and then child ::after
  &__radio-input:checked ~ &__radio-label &__radio-button::after {
    opacity: 1;
  }
}

This is the nutshell of the form and let’s take a look some important classes.

form__input

Mainly it has all common css properties such as font-size, border, padding and so on. Things I would like to notes are pseudo classes such as :focus, :invalid, ::-webkit-input-placeholder.

:focus is selected when input is selected (focus). Since I didn’t want any default behavior, it is overriden that it has bottom outline with green color and box shadow

:invalid is selected when the input is evaluated to be invalid. Take a look at email address example in the video. Since I used input email type in the html, it will automatically evaluate as I type the letters. &:focus:invalid means I only want to show orange bottom color to indicate the error only if the input is focused and invalid

::-webkit-input-placeholder is to style placeholder text in the input.

form__label

The class itself is not that special if you take a look at it but I still want to go over since this is the place animation is happening.
Initially I want to hide the label but want to display via animation once the user types in the input. How do I do that?

&__input:placeholder-shown is the pseudo class when placeholder text in the input is shown – nothing is typed yet. I need to use the class because I want to animate the label only when input is focused and something is typing. For this, you can use a sibling selector.
form__label is a direct sibling of the input so the line &__input:placeholder-shown + &__label will select the label when nothing is in the input. Since I am hiding everything, I set opacity to 0, and visibility is hidden to make it completely gone.

Once the user types something, then &__input:placeholder-shown + &__label is not selected and label is the only effective one. That’s how the animation is happening. Please note that + is the one making sibling selector. It only looks for direct sibling which is very sensitive to the order of the elements.

How to build a css component for radio button?

You cannot style radio button directly. Then, how can I apply CSS style? You can hide the original button and create a CSS component to look like radio button. It’s okay to hide the original radio button because it will still be selected thanks to form-group and the matching label.

If you look at &__radio-button, it has all the styles to make it look like an outline button. I had to use absolute position to place the button nicely. Please note that parent class also needs to specify the position, either relative or absolute.

Now, how do I create another circle inside the button outline when it’s clicked? We can use :checked property.
&__radio-input:checked ~ &__radio-label &__radio-button::after means once radio input is selected :checked will be enabled then look for a sibling called form__radio-label which is just a sibling (+ direct sibling, ~ general sibling, you could have used + here but just wanted to show ~ too) then selects ::after pseudo elements. Please note that initial opacity is 0 for ::after but if clicked, opacity now is 1 which creates another circle.

CSS – video and shape-outside

In this post, I am going to show how to implement a webpage that plays a background video and let texts floats around the image.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.
Let’s take a look at the example demo first.

Example Demo

As you can see in the above example, background video is playing. You will also notice that texts are floating around the image (circle shape) and image gets blurred when mouse hover over the image. It is actually pretty simple to do and let’s take a look at the code!

HTML Code

<section class="section-stories">
    <div class="bg-video">
        <video class="bg-video__content" autoplay muted loop>
            <source src="img/video.mp4" type="video/mp4">
            <source src="img/video.webm" type="video/webm">
            Your browser is not supported!
        </video>
    </div>
    <div class="u-center-text u-margin-bottom-big">
        <h2 class="heading-secondary">
            This is a test page
        </h2>
    </div>

    <div class="row">
        <div class="story">
            <figure class="story__shape">
                <img src="img/nat-8.jpg" alt="Person on a tour" class="story__img"/>
                <figcaption class="story__caption">Jade Moore</figcaption>
            </figure>
            <div class="story__text">
                <h3 class="heading-tertiary u-margin-bottom-small">This is great!</h3>
                <p>
                    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eligendi iure itaque est obcaecati consequuntur perspiciatis hic quasi quisquam mollitia reiciendis ipsum fugit, sequi, minima accusantium earum nam ad. Voluptate, nulla!
                </p>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="story">
            <figure class="story__shape">
                <img src="img/nat-9.jpg" alt="Person on a tour" class="story__img"/>
                <figcaption class="story__caption">Will Smith</figcaption>
            </figure>
            <div class="story__text">
                <h3 class="heading-tertiary u-margin-bottom-small">I like this!</h3>
                <p>
                    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eligendi iure itaque est obcaecati consequuntur perspiciatis hic quasi quisquam mollitia reiciendis ipsum fugit, sequi, minima accusantium earum nam ad. Voluptate, nulla!
                </p>
            </div>
        </div>
    </div>
    <div class="u-center-text u-margin-top-huge">
        <a href="#" class="btn btn-text">Read all stories →</a>
    </div>
</section>

There are two main parts – div with bg-video class and two rows with story class.
Note that the reason I put multiple source in video tag is to assure video is loaded and played for all browsers. There is a couple of video properties worth to mention. autoplay makes video played automatically when the page is loaded. muted make sure it doesn’t make any sound (because it’s a background video). loop makes sure video replays forever.

CSS Code

.section-stories {
  padding: 15rem 0;
  position: relative;
}

.story {
  width: 75%;
  margin: 0 auto;
  box-shadow: 0 3rem 6rem rgba($color-black, .1);
  background-color: rgba($color-white, .6);
  border-radius: 3px;
  padding: 6rem;
  padding-left: 9rem;
  font-size: $default-font-size;
  transform: skewX(-12deg);

  &__shape {
    // has to be floated and width and height for circle
    width: 15rem;
    height: 15rem;
    float: left;
    // vectorized shape
    // 7.5 rem radius at exactly center (50%, 50%)
    // define where the contents floats around the symbol which is circle
    -webkit-shape-outside: circle(50% at 50% 50%);
    shape-outside: circle(50% at 50% 50%);

    -webkit-clip-path: circle(50% at 50% 50%);
    clip-path: circle(50% at 50% 50%);
    transform: translateX(-3rem) skewX(12deg);

    position: relative;
  }

  &__img {
    height: 100%;
    transform: translateX(-4rem) scale(1.4);
    backface-visibility: hidden;
    transition: all .5s;
  }

  &__text {
    transform: skewX(12deg);
  }

  &__caption {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, 0);
    color: $color-white;
    text-transform: uppercase;
    font-size: 1.7rem;
    text-align: center;
    opacity: 0;
    transition: all .5s;
    backface-visibility: hidden;
  }

  &:hover &__caption {
    opacity: 1;
    transform: translate(-50%, -50%);
  }

  &:hover &__img {
    transform: translateX(-4rem) scale(1);
    filter: blur(3px) brightness(80%);
  }
}

.bg-video {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  z-index: -1;
  opacity: .15;
  overflow: hidden;

  &__content {
    height: 100%;
    width: 100%;

    // element will fill the parent element while maintaining aspect ratio
    object-fit: cover;
  }
}

This is the entire SCSS code for the full picture. We will take a look at each class to see more details.

SCSS – story class

.story {
  width: 75%;
  margin: 0 auto;
  box-shadow: 0 3rem 6rem rgba($color-black, .1);
  background-color: rgba($color-white, .6);
  border-radius: 3px;
  padding: 6rem;
  padding-left: 9rem;
  font-size: $default-font-size;
  transform: skewX(-12deg);

  &__shape {
    // has to be floated and width and height for circle
    width: 15rem;
    height: 15rem;
    float: left;
    // vectorized shape
    // 7.5 rem radius at exactly center (50%, 50%)
    // define where the contents floats around the symbol which is circle
    -webkit-shape-outside: circle(50% at 50% 50%);
    shape-outside: circle(50% at 50% 50%);

    -webkit-clip-path: circle(50% at 50% 50%);
    clip-path: circle(50% at 50% 50%);
    transform: translateX(-3rem) skewX(12deg);

    position: relative;
  }

  &__img {
    height: 100%;
    transform: translateX(-4rem) scale(1.4);
    backface-visibility: hidden;
    transition: all .5s;
  }

  &__text {
    transform: skewX(12deg);
  }

  &__caption {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, 0);
    color: $color-white;
    text-transform: uppercase;
    font-size: 1.7rem;
    text-align: center;
    opacity: 0;
    transition: all .5s;
    backface-visibility: hidden;
  }

  &:hover &__caption {
    opacity: 1;
    transform: translate(-50%, -50%);
  }

  &:hover &__img {
    transform: translateX(-4rem) scale(1);
    filter: blur(3px) brightness(80%);
  }
}

This is the class with the largest code but if you loo closer it’s not that complicated. In parent story class, I used skewX to give a shape to the rectangle that surrounds the image and the text. If you just skew once, it will skew everything including the text and the image. That’s why I skewed back in each &__text and &__shape.

In order to have circle shape, we can use clip-path css property with circle value. Note that circle required width, height and floats properties. Then, you can use shape-outside css property of circle which will make texts next to the shape floats around the circle. Note that shape-outside itself won’t make circle shape. It just creates a virtual circle and make text floats. clip-path is the property to make it circle.

For blur, zoom-in effect when you hover, I just used opacity, filter, and transform property. Filter is the one that makes it darker and blur.

SCSS – bg-video class

.bg-video {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  z-index: -1;
  opacity: .15;
  overflow: hidden;

  &__content {
    height: 100%;
    width: 100%;

    // element will fill the parent element while maintaining aspect ratio
    object-fit: cover;
  }
}

Video is actually really simple. I used absolute position (note that position relative is used in section-stories class to anchor the video) to make it a background. z-index=-1 so that it doesn’t hide any components such as stories and button.

It is worthwhile to explain object-fit css property. object-fit property will make the element fill the parent element while maintaining aspect ratio. If you comment out the property, you will see the size of the video doesn’t always match the parent element. Controlling with widht/height will be hard because of aspect ratio. However, with object-fit property, it will automagically fill the parent element and maintain the aspect ratio. Here I used cover value but there are other properties you can use such as fill.

SCSS – Flipping Card Component

Today, I am going to implement a CSS card that you can flip round when you hover the mouse using SCSS.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.
Main CSS properties I use are perspective, backface-visibility, background-blend-mode.
Let’s jump to the code directly and explain each part

Example

HTML Code

<div class="card">
    <div class="card__side card__side--front">
        <div class="card__picture">
             
        </div>
        <h4 class="card__heading">
            <span class="card__heading-span">
                Front Side
            </span>
        </h4>
        <div class="card__details">
            <ul>
                <li>Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet nemo, qui cum excepturi repudiandae dolorum, ex necessitatibus iusto quo vitae maxime itaque ad accusamus. Vero eveniet quam ipsam nihil? Quibusdam!</li>
            </ul>
        </div>
    </div>
    <div class="card__side card__side--back">
        <div class="card__cta">
            <div class="card__price-box">
                <p class="card__price-value">Back Side</p>
            </div>
        </div>
    </div>
</div>

CSS Code

Both front/back card size will be children of card class. Since I use absolute position for the children classes we need to have relative position in the parent. The most important thing is perspective. As you can see in the video, we need perspective property to give flipping visual effect. I chose 150rem because a smaller number gives more dramatic flipping.

.card {
  // FUNCTIONALITY

  // perspective has to be in parent
  perspective: 150rem;
  -moz-perspective: 150rem;
  position: relative;
  height: 50rem;

  &__side {
    height: 50rem;
    transition: all .8s ease;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;

    // hides the back part of the element
    backface-visibility: hidden;

    border-radius: 3px;
    overflow: hidden;
    box-shadow: 0 1.5rem 4rem rgba($color-black, .15);

    &--front {
      background-color: $color-white;
    }

    &--back {
      transform: rotateY(180deg);
      background-image: linear-gradient(
          to right bottom, 
          $color-secondary-light, 
          $color-secondary-dark);
    }
  }

  // when hover, I want .card__side--front to transform
  &:hover &__side--front {
    transform: rotateY(-180deg);
  }

  &:hover &__side--back { 
    transform: rotateY(0);
  }

  // FRONT SIDE STYLING
  &__picture {
    background-size: cover;
    height: 23rem;
    background-blend-mode: screen;
    -webkit-clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);
    clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);

    background-image: linear-gradient(to right bottom, $color-secondary-light, $color-secondary-dark),
      url(../img/nat-5.jpg);
  }

  &__heading {
    font-size: 2.8rem;
    font-weight: 300;
    text-transform: uppercase;
    text-align: right;
    color: $color-white;
    position: absolute;
    top: 12rem;
    right: 2rem;
    width: 75%;
  }

  &__heading-span {
    padding: 1rem 1.5rem;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
    
    background-image: linear-gradient(
        to right bottom, 
        rgba($color-secondary-light, .85), 
        rgba($color-secondary-dark, .85));
  }

  &__details {
    padding: 3rem;

    ul {
      list-style: none;
      width: 80%;
      margin: 0 auto;

      li {
        text-align: center;
        font-size: 1.5rem;
        padding: 1rem;

        &:not(:last-child) {
          border-bottom: 1px solid $color-grey-light-2;
        }
      }
    }
  }
}

This is a pretty long code and let’s take a look at each class.

CSS – card__side

This class represents a class of both front/back side. Let’s take a look at closer look.

  &__side {
    height: 50rem;
    transition: all .8s ease;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;

    // hides the back part of the element
    backface-visibility: hidden;

    border-radius: 3px;
    overflow: hidden;
    box-shadow: 0 1.5rem 4rem rgba($color-black, .15);

    &--front {
      background-color: $color-white;
    }

    &--back {
      transform: rotateY(180deg);
      background-image: linear-gradient(
        to right bottom, 
        $color-secondary-light, 
        $color-secondary-dark);
    }
  }

// when hover, I want .card__side--front to transform
  &:hover &__side--front {
    transform: rotateY(-180deg);
  }

  &:hover &__side--back { 
    transform: rotateY(0);
  }

Since we have two sides and they need to be in the same position to flip, I used position absolute – top:0, left: 0. This is why I used position:relative in the parent card class.

Note that I put rotateY(180deg) on backside because they need to stay on 180 degree flipped while the mouse hovers over the component.

Note that on hover state I also specified &__side–front/back to transform the card whenever the mouse hover the card.

CSS – card__picture

// FRONT SIDE STYLING
  &__picture {
    background-size: cover;
    height: 23rem;
    background-blend-mode: screen;
    -webkit-clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);
    clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);

    background-image: linear-gradient(to right bottom, $color-secondary-light, $color-secondary-dark),
      url(../img/nat-5.jpg);
  }

It is not just an ordinary picture. It is actually blended to linear-gradient color I specified. The property for the blend is background-blend-mode. There are multiple blend mode you can explorer but I used screen here. I also used clip-path to clip the image to make it look nicer.

CSS – card__heading

  &__heading {
    font-size: 2.8rem;
    font-weight: 300;
    text-transform: uppercase;
    text-align: right;
    color: $color-white;
    position: absolute;
    top: 12rem;
    right: 2rem;
    width: 75%;
  }

  &__heading-span {
    padding: 1rem 1.5rem;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
    
    background-image: linear-gradient(
        to right bottom, 
        rgba($color-secondary-light, .85), 
        rgba($color-secondary-dark, .85));
  }

Heading is on top of the image. I used absolute position again in order to manually place the heading on the image.
I am going to skip explanation about. details as it’s pretty simple.

Now we have a nice looking and working flipping card component!

CSS – skew property and icon-fonts

This is a simple example showing how to design a cool page using css skew property and icon-fonts.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.

Let’s first take a look at the example picture we are going to build

As you can see, the background image is skewed but not the contents inside. And background-clip text is also used to have a color in the icon-fonts. Let’s see how we can do that

Download icon-fonts

You can use any of your favorite icon-fonts but I downloaded mine from this website – https://linea.io/

HTML Code

The icon-fonts I downloaded are icon-basic-word, icon-basic-compass, icon-basic-map, icon-basic-heart

<section class="section-features">
    <div class="row">
        <div class="col-1-of-4">
            <div class="feature-box">
                <i class="feature-box__icon icon-basic-world"></i>
                <h3 class="heading-tertiary u-margin-bottom-small">Card 1</h3>
                <p class="feature-box__text">
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe esse dolor repudiandae 
                </p>
            </div>
        </div>

        <div class="col-1-of-4">
            <div class="feature-box">
                <i class="feature-box__icon icon-basic-compass"></i>
                <h3 class="heading-tertiary u-margin-bottom-small">Card 2</h3>
                <p class="feature-box__text">
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe esse dolor repudiandae 
                </p>
            </div>
        </div>

        <div class="col-1-of-4">
            <div class="feature-box">
                <i class="feature-box__icon icon-basic-map"></i>
                <h3 class="heading-tertiary u-margin-bottom-small">Card 3</h3>
                <p class="feature-box__text">
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe esse dolor repudiandae 
                </p>
            </div>
        </div>

        <div class="col-1-of-4">
            <div class="feature-box">
                <i class="feature-box__icon icon-basic-heart"></i>
                <h3 class="heading-tertiary u-margin-bottom-small">Card 4</h3>
                <p class="feature-box__text">
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe esse dolor repudiandae 
                </p>
            </div>
        </div>
    </div>
</section>

CSS Code

Please note that I used SCSS for the style. You can still use CSS but just make sure to replace all the SCSS variables properly.
Let’s take a look at feature-box first.

$color-primary-light: #add8e6;
$color-primary-dark: #00008b;
$color-white: #fff;
$color-black: #000;

.feature-box {
  background-color: rgba($color-white, .8);
  font-size: 1.5rem;
  padding: 2.5rem;
  text-align: center;
  border-radius: 3px;
  box-shadow: 0 1.5rem 4rem rgba($color-black, .15);
  transition: transform .3s;
  
  &__icon {
    font-size: 6rem;
    margin-bottom: .5rem;
    display: inline-block;
    background-image: linear-gradient(to right, $color-primary-light, $color-primary-dark);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  &:hover {
    transform: translateY(-1.5rem) scale(1.03);
  }
}
  • In the feature-box class, I used & which means to use the parent path up to this point – feature-box__icon.
  • In &__icon, I used background-clip to have colors on icon-fonts. Please note that you need to set color transparent.
  • Although you cannot see in the picture, if you hover over the card, you will see it scales up little bit and translate upward for some visual effects.

Now let’s take a look at section features where the image is loaded and skew is applied

.section-features {
  padding: 20rem 0;
  background-image: linear-gradient(
    to right bottom, 
    rgba($color-primary-light, 0.8), 
    rgba($color-primary-dark, 0.8)), 
  url("../img/nat-4.jpg");
  background-size: cover;
  transform: skewY(-7deg);
  margin-top: -10rem;

  // every direct child
  & > * {
    transform: skewY(7deg);
  }
}

In order to skew the background image, you simply can use transform: skewY(degree). In the above example, I skewed 7 degrees counter clockwise. But if you only skew once, you will see everything is skewed including all the texts. To prevent that we skew back all the direct children – & > * 7 degrees to make it even.

I did not post the column css class here as it’s explained in this post – https://nycomdorics.com/sass-float-grid/

CSS – background-clip property

background-clip property enables you to display until what area/contents the background.
There are 4 types of background-clip: border-box, padding-box, content-box, text.
Each type represents the boundary of the background render. border-box means the background will be rendered to the border.
padding-box to the padding, content-box to the content, and text-box to the text.

Example

It would be much easier if you see the example.

border-box
padding-box
content-box
text

HTML Code

Here is the code for html

<div class="border-box">This is background clip border box</div>
<div class="padding-box">This is background clip padding box</div>
<div class="content-box">This is background clip content box</div>
<div class="text-box">This is background clip text box</div>

CSS Code

Here is the code for CSS. Please note that I used transparent in text class so that the color will be displayed.

div {
  border: .8em darkviolet;
  border-style: double;
  margin: 1em 0;
  padding: 1.4em;
  background: linear-gradient(to right, #7ed56f, #28b485);
  font: 900 1.2em sans-serif;
}

.border-box {
  background-clip: border-box;
}

.padding-box {
  background-clip: padding-box;
}

.content-box {
  background-clip: content-box;
}

.text-box {
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

CSS SASS float grid explained

There is a couple of ways to implement CSS grid. Although float grid is not the most recommended method I still wanted to do that for academic purpose.

In this example, I am going to implement a CSS grid like the image below. There will be 6 rows total and each row will have its own columns.

HTML Code

Here is the HTML code showing how each row/columns are respresented. There will be 6 css classes to represent each column.
1. col-1-of-2: column size 1 out of 2 (50%)
2. col-1-of-3: column size 1 out of 3 (33%)
3. col-1-of-4: column size 1 out of 4 (25%)
4. col-2-of-3: column size 2 out of 3 (66%)
5. col-2-of-4: column size 2 out of 4 (50%)
6. col-3-of-4: column size 3 out of 4 (75%)

<section class="grid-test">
    <div class="row">
        <div class="col-1-of-2">
            Col 1 of 2
        </div>
        <div class="col-1-of-2">
            Col 1 of 2
        </div>
    </div>
    
    <div class="row">
        <div class="col-1-of-3">
            Col 1 of 3
        </div>
        <div class="col-1-of-3">
            Col 1 of 3
        </div>
        <div class="col-1-of-3">
            Col 1 of 3
        </div>
    </div>
    
    <div class="row">
        <div class="col-1-of-3">
            Col 1 of 3
        </div>
        <div class="col-2-of-3">
            Col 2 of 3
        </div>
    </div>
    
    <div class="row">
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
    </div>
    
    <div class="row">
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-2-of-4">
            Col 2 of 4
        </div>
    </div>
    
    <div class="row">
        <div class="col-1-of-4">
            Col 1 of 4
        </div>
        <div class="col-3-of-4">
            Col 3 of 4
        </div>
    </div>
</section>

CSS (SASS) Code

There is a couple of things to note.

  • :not(:last-child) means select everything except the last child because we don’t want the last child to have margin bottom.
  • attribute selector [] in line 27. Note that there is a common code for all the column classes and we don’t want to repeat that. attribute selector is used in order to solve duplicate code. [class^=”col-“] means to select all the elements with the class attributes starts with ‘col-‘ string. It also implies that you can use any attributes to select elements.
  • calc is a provided function that can calculate an equation. It is able to accept % in the equation.
$grid-width: 114rem;
$gutter-vertical: 8rem;
$gutter-horizontal: 6rem;

@mixin clearfix {
  &::after {
    content:  "";
    display: table;
    clear: both;
  }
}

.row {
  max-width: $grid-width;
  background-color: #eee;
  margin: 0 auto;

  &:not(:last-child) {
    margin-bottom: $gutter-vertical;
  }

  @include clearfix;
  // select all the elements with the class attributes starts with 'col-'
  // ^ start with
  // * contain
  // $ end with
  [class^="col-"] {
    color: white;
    height: 5rem;
    font-size: 3rem;
    background-color: orangered;
    float: left;

    &:not(:last-child) {
      margin-right: $gutter-horizontal;
    }
  }

  .col-1-of-2 {
    width: calc((100% - #{$gutter-horizontal}) / 2);
  }

  .col-1-of-3 {
    width: calc((100% - 2 * #{$gutter-horizontal}) / 3);
  }

  .col-1-of-4 {
    width: calc((100% - 3 * #{$gutter-horizontal}) / 4);
  }

  .col-2-of-3 {
    width: calc(2 * ((100% - 2 * #{$gutter-horizontal}) / 3) + #{$gutter-horizontal});
  }

  .col-2-of-4 {
    width: calc(2 * ((100% - 3 * #{$gutter-horizontal}) / 4) + #{$gutter-horizontal});
  }

  .col-3-of-4 {
    width: calc(3 * ((100% - 3 * #{$gutter-horizontal}) / 4) + 2 * #{$gutter-horizontal});
  }
}

How each equation is decided

  • col-1-of-2
    Check the first row. You only have 2 columns and 1 gutter. The width of pure columns is (100% – gutter). Then since there are two columns in the row you need to divide it by 2. The width of a single column is then (100% – gutter) / 2
  • col-1-of-3
    Check the second row. You have 3 columns and 2 gutters. The width of pure columns is (100% – 2 * gutter). Then since there are three columns in the row you need to divide it by 3. The width of a single column is then (100% – 2 * gutter) / 3
  • col-2-of-3
    This one seems to be a bit tricky but it’s actually pretty simple. If you look at row 2, 2-of-3 is actually the sum of two col-1-of-3 and one gutter.
    The width of a single column is then (2 * 2-of-3 + gutter)
  • col-3-of-4
    This is the exact same case as the above. This is the sum of three col-1-of-4 and two gutters.
    The width of a single column is then (3 * 1-of-4 + 2 * gutter)

React Styled Component V5 Basics

Styled component is a very useful and convenient library for react styling. Although there are many other choices (or you don’t even need to use as you can directly apply css) there is a definite advantage such as performance.

Install

Make sure react app is created by running the following command

> npx create-react-app <your app name>

After successful creation, run

> npm install styled-components

Basic Usage

Let’s create a button react component and apply some css. In order to use styled component you just need to choose styled.<component> – in this case I used button but you can use div, h1, span and etc – and apply css styles there.

There is more than just normal css support. You can apply javascript logic in order to decide certain styles based on provided props. As you can see in the example code ‘p’ represents prop.

Styled component also supports bulk styling selection by using css.

// Button.js

import React from 'react';
import styled, {css} from "styled-components";

const ButtonContainer = styled.button`
  color: white;
  background: ${p => p.secondary ? 'black' : '#f8049c'};
  font-weight: bold;

  ${p => p.large ? css`
    padding: 10px;
    border-radius: 5px;
    font-size: 1.5em;
  ` : css`
    padding: 8px;
    border-radius: 4px;
    font-size: 1em;
  `}
  
  box-shadow: none;
  border: one;
  width: 100%;
  display: block;
  white-space: none;

  &:disabled{
    background: #eee;
    color: #666;
  }
`;

function Button(props) {
  return <ButtonContainer {...props}/>
} 

export {Button};

You can also apply global styles so you don’t have to copy code every place.
In order to have global style make sure

  1. import ‘createGlobalStyle’ from styled components
  2. create global style and apply css
  3. render the created component in App
import React from 'react';
import {Button} from 'components/common';
import {createGlobalStyle} from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    background: white;
    min-height: 100vh;
    margin: 0;
    color: black;
    font-family: 'Kaushan Script';
  }
`;


function App() {
  return (
    <>
      <GlobalStyle />
      <h1>App</h1>
      <Button primary>
        Primary Test
      </Button>
      <Button secondary>
        Secondary Test
      </Button>
      <Button large>
        Large Test
      </Button>
    </>
    
  );
}

export default App;

CSS – animation using keyframe

This example code tells you how to do animation using css keyframe.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.

Example

animation using keyframe

Example Code

HTML code

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700,900" rel="stylesheet">

        <link rel="stylesheet" href="css/icon-font.css">
        <link rel="stylesheet" href="css/style.css">
        <link rel="shortcut icon" type="image/png" href="img/favicon.png">
        
        <!-- <title>Natours | Exciting tours for adventurous people</title> -->
        <title>clip-path and linear-gradient</title>
    </head>
    <body>
        <header class="header">
            <div class="logo-box">
                <img src="img/logo-white.png" alt="Logo" class="logo"/>
            </div>

            <div class="text-box">
                <h1 class="heading-primary">
                    <span class="heading-primary-main">Primary</span>
                    <span class="heading-primary-secondary">Secondary</span>
                </h1>
            </div>
        </header>
    </body>
</html>

CSS code

The css code below uses keyframe for animation which gives a way to control how the intermediate steps of the animation should be by defining actions for each percentage of the animation duration.

As you can see, you need to define keyframes so that you can use it in other place by animation property. When defining keyframes, you need to specify the percentage of the duration. For example, 0% means the start of the animation and 100% means the end.

In the example code below, I have defined two animations – moveInLeft/moveInRight. The moveInLeft makes the element move to the right and vice versa for the moveInRight. I can achieve the goal by defining translate position. You can also use other functions such as rotate(deg). In moveInLeft keyframe, the element starts with -100px position in the beginning and move to 10px at 80% of duration and 0 when done.

After defining the keyframe, you need to use the keyframe in the css element to use it. Typical properties are animation-name, animation-duration and animation-timing-function. You can use the keyframe name for animation-name. animation-duration represents the entire duration of the animation. animation-timing-function represents how the timing of the animation should be. For example, you can use ease-out, ease-in. (more timing function defined in MDN documents). animation-iteration-count represents how many times the animation should be played. You can specify all those properties explicitly or you can do everything in one line like in the heading-primary-secondary example.

.heading-primary-main {
  display: block;
  font-size: 60px;
  font-weight: 400;
  letter-spacing: 35px;

  animation-name: moveInLeft;
  animation-duration: 1s;
  animation-timing-function: ease-out;
  
  /* animation-iteration-count: 3; */
  /* animation-delay: 3s; */
}

.heading-primary-secondary {
  display: block;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 17.4px;

  animation: moveInRight 1s ease-out;
}

@keyframes moveInLeft {
  0% {
    opacity: 0;
    transform: translateX(-100px);
  }

  80% {
    transform: translateX(10px);
  }

  100% {
    opacity: 1;
    transform: translate(0);
  }
}

@keyframes moveInRight {
  0% {
    opacity: 0;
    transform: translateX(100px);
  }

  80% {
    transform: translate(-10px);
  }

  100% {
    opacity: 1;
    transform: translate(0);
  }
}

CSS – Place elements in the center of the screen

This is to place html elements in the center. In this example, it uses absolute/relative position and transform (translate) in order to place properly.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.

Example

Please note that there are two texts here – primary, secondary. They are in same h1 but in different span in order to manage it easily.

Example Code

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700,900" rel="stylesheet">

        <link rel="stylesheet" href="css/icon-font.css">
        <link rel="stylesheet" href="css/style.css">
        <link rel="shortcut icon" type="image/png" href="img/favicon.png">
        
        <!-- <title>Natours | Exciting tours for adventurous people</title> -->
        <title>clip-path and linear-gradient</title>
    </head>
    <body>
        <header class="header">
            <div class="text-box">
                <h1 class="heading-primary">
                    <span class="heading-primary-main">Primary</span>
                    <span class="heading-primary-secondary">Secondary</span>
                </h1>
            </div>
        </header>
    </body>
</html>

As you can see the above code, this is nested in a couple of levels. div with class text-box is the place where I will use absolute position in the css code. But you have to provide a reference point of that position. That’s where header element will include so that the child will always be in the center of the parent – header – and parent will be placed for the responsive view.

Another thing to note is top, left which specifies the left, top position of the child element. For example, if you just specify top 50%, left: 50%, you will see the text is not located in the center because the positions actually mean the top left point of the element. That’s why we need to transform the text accordingly in order to place it in the center. You can use transform/translate property in order to move the child element.

.header {
  height: 95vh;
  background-image: linear-gradient(
    to right, 
    #7ed56fb0, 
    #28b4858e), 
  url("../img/hero.jpg");
  background-size: cover;
  background-position: top;
  
  /* this is for logo-box */
  position: relative;

  /* Trapezoid */
  clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
  
  /* Triangle */
  /* clip-path: polygon(0 0, 100% 50%, 0 100%) */
  
  /* you can use pixel or vh */
  /* clip-path: polygon(0 0, 100% 0, 100% 75vh, 0 100%); */
}

.text-box {
  position: absolute;
  top: 45%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.heading-primary {
  color: #fff;
  text-transform: uppercase;

}

.heading-primary-main {
  display: block;
  font-size: 60px;
  font-weight: 400;
  letter-spacing: 35px;
}

.heading-primary-secondary {
  display: block;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 17.4px;
}

CSS – background image with linear-gradient and clip-path

You can clip background image by using clip-path in css to make it look nicer.
You can also use multiple properties for background-image property in css. In this example, I used linear-gradient (green) and clip-path properties.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.

Example Picture

Trapezoid clip
Triangle

HTML Code

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700,900" rel="stylesheet">

        <link rel="stylesheet" href="css/icon-font.css">
        <link rel="stylesheet" href="css/style.css">
        <link rel="shortcut icon" type="image/png" href="img/favicon.png">
        
        <title>clip-path and linear-gradient</title>
    </head>
    <body>
        <header class="header">

        </header>
    </body>
</html>

CSS

You need to use clip-path to use polygon shaped image. You need to provide points (coordinates) of value pair x (horizontal), y (vertical) for your case.
For example, you will need to provide 4 points for rectangle and 3 for triangle. The order of the point always starts from left top and clockwise.
Please note that you can use multiple properties for background-image separated by comma. In this example, I used linear-gradient and URL to load the image

.header {
  height: 95vh;
  background-image: linear-gradient(
    to right, 
    #7ed56fb0, 
    #28b4858e), 
  url("../img/hero.jpg");
  background-size: cover;
  background-position: top;

  /* Trapezoid */
  clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
  
  /* Triangle */
  clip-path: polygon(0 0, 100% 50%, 0 100%)
  
  /* you can use pixel or vh */
  /* clip-path: polygon(0 0, 100% 0, 100% 75vh, 0 100%); */
}