This project was inspired by the final challenge of the From Figma To Code course on Coursera. Prior to taking the course, I built only from PDF design files. I took the course to learn to build sites from Figma
design files which is more typical in professional environment. The course was taught in HTML CSS and JavaScript
but I have implemented this solution in React-TypeScript
to enhance functionality and maintainability.
I was required to build a responsive webpage from this given Figma file
Users should be able to:
- View the optimal layout for the site depending on their device's screen size
- See hover states for all interactive elements on the page
- I implemented the solution in
React-TypeScript
, even though the course was taught inHTML, CSS, and JavaScript
, to enhance functionality and maintainability. - I implemented a cool animation for the drone image in the 'hero' section.
- I implemented
client-side form validation
for the email signup section.- On submission, user receives error message with error icon if any input field is empty.
- User receives error message if email is not formatted correctly.
Mobile screen - nav toggle on:
Mobile screen - nav toggle off:
- Semantic HTML5 markup
- CSS custom properties
- CSS Modules
- Flexbox - CSS web layout model
- CSS grid - CSS web layout model
- TypeScript - Programming language that extends JavaScript
- React - JavaScript library
- Node.js - JavaScript runtime environment
- Vite - React build tool with local development server
- I learned a more advanced way of using
CSS Grid
. I learned that I could definegrid template areas
and assign specific content to them giving me more control over layout and design. I applied this in the 'Footage' section of the page to realise the layout of the gallery of images.
.gallery {
display: grid;
grid-template-areas:
". a b"
"c d ."
". e .";
@media (min-width: 900px) {
width: min(100% - 18.274rem, 73.18%);
/* to remember how you came about it add the two values to the two values of the width of .text-container
You'll get 100%+4.851rem in both cases cuz they are to sit side by side with 2rem between and overflow by 6.851rem*/
margin-left: auto;
transform: translateY(-16.667%);
}
}
.gallery img:nth-of-type(1) {
grid-area: a;
}
.gallery img:nth-of-type(2) {
grid-area: b;
}
.gallery img:nth-of-type(3) {
grid-area: c;
}
.gallery img:nth-of-type(4) {
grid-area: d;
}
.gallery img:nth-of-type(5) {
grid-area: e;
}
.gallery img {
object-fit: cover;
aspect-ratio: 1 / 1;
}
- I learned more advanced ways of manupulating
background-image
. I learned that I could blend an image with a specific color by setting the solid color as background of the element, then creating a::before
psedo-element with the image as background to sit over the original element. Then, I apply an opacity to the pseudo-element such that the solidbackground-color
beneath seeps through. I needed this to realize the design of the 'Quote' section.
.quote-section {
text-transform: uppercase;
font-family: CustomHeadingFont;
padding: 3.813rem 0 22.75rem;
color: #ffffff;
background-color: #303853;
position: relative;
@media (min-width: 900px) {
padding: 15.563rem 0 15.375rem;
}
}
.quote-section::before {
content: "";
position: absolute;
top: 0;
left: 0;
background-image: url(../assets/img/stadium.png);
background-size: cover;
background-position: 8%;
width: 100%;
height: 100%;
opacity: 17%;
}
- I also learned about the
background-blend-mode
property which is used to blend various background layers of an element. I learned that setting it to 'screen' makes thebackground-image
lighter and setting it to 'multiply' darkens the image. There are alot of other values which I have to study later but I usedbackground-blend-mode:screen
to implement the design of the 'Hero' section.
.hero {
background-color: #b2dd9e;
background-image: url(../assets/img/speed-trails.png);
background-size: cover;
background-position: center;
position: relative;
padding: 8.25rem 0 6.688rem;
background-blend-mode: screen;
@media (min-width: 900px) {
padding: 26.688rem 0;
}
}
- I learned how to apply animations using CSS by defining an animation in
keyframes
. I used this to animate the drone image in 'Hero'section, to appear to hover up and down, and for the shadow to get darker when the drone is closer to the ground and lighter when drone goes up.
.drone {
position: relative;
}
.drone-body {
position: relative;
animation: hover 2s alternate-reverse infinite;
}
.drone-shadow {
position: absolute;
left: 0;
top: 10%;
opacity: 0.4;
animation: pulse 2s alternate-reverse infinite;
}
@keyframes hover {
from {
transform: translateY(-30px);
}
}
@keyframes pulse {
from {
opacity: 0;
}
}
/* remember you can also define the "to" which uses the normal set state of the properties if not set(e.g opacity:.4 in this case).
You can also use percentages like "0%"" for "from" and "100%"" for 'to'. You can even add intermediaries like 50%
Also know that "pulse" and "hover" are not keywords. You can use any word and define it */
- I found a good use case for the
clamp
CSS feature in my menu bar positioning (desktop version). I was able to make my menu bar static within a certain screen-size range, then move responsively within another range, and then stay static again within a third range using theclamp
feature. Also, since font size can use thevw
unit andclamp
can take three values, I am able to declare font sizes for three ranges of viewport widths without a media query. Having delved deep into the capabilities ofclamp
, I am now able to implement dynamic and responsive behaviours that would have otherwise needed multiple media query breakpoints.
.menu {
position: absolute;
top: 0;
right: 0;
background-color: #363b4e;
width: clamp(200px, 447%, 300px);
height: 100%;
display: flex;
flex-direction: column;
align-items: flex-end;
padding: 2.313rem 2.688rem;
transition: clip-path 0.3s ease-in-out;
@media (min-width: 900px) {
right: auto;
left: clamp(-240.9px, 261% - 1245.1px, -58.3px);
/*Note: you intentionally solved for those clamp values to make sure that at breakpoint 900px, the left edge of the parent i.e ".nav"
pins ".menu" at exactly between REGISTER AND FAQ, then at 1100px, ".menu" is let loose and it moves relative to left edge of parent
until at 1300px when it is pinned again and finally at exactly between HOME and RACES to match the given 1440px desktop design*/
background-color: transparent;
width: auto;
height: auto;
flex-direction: row;
align-items: center;
padding: 0;
margin-top: 1.438rem;
}
}
.title {
font-family: CustomHeadingFont;
text-transform: uppercase;
font-size: clamp(5vw, 2.25rem, 9vw); /*dynamic font size*/
font-weight: 400;
line-height: 0.916;
width: 90%;
padding: 0.806em 0 0.667em 15%;
margin-bottom: 1.083em;
@media (min-width: 900px) {
display: inline-block;
width: auto;
font-size: 4rem;
padding: 0.672em 0.739em 0.391em;
padding-left: calc(20% - 6.851rem);
margin-bottom: 0.906em;
}
}
- Finally and generally, I learned to work with
Figma
design files. I have gotten familiar with reading typography, layout, and color specifications directly from Figma. I have also learnt to grab assets and text directly from the Figma design.
- Building from Figma designs
- Z-index
- Mobile-first CSS
- CSS Flexbox
- CSS Grid
- CSS animations
- CSS clamp feature
- Media queries
I found these techniques very useful. I will continue focusing on them in future projects to refine and perfect them.
- Controlling background-images | CSS Tutorial
- Background images with HTML & CSS
- min(), max(), and clamp() are CSS magic!
- Solve your z-index issues | z-index and stacking context explained
- Blend background images and colors with CSS | #shorts
- How to use mix-blend-mode, and how to avoid problems with it
These YouTube tutorials were really helpful and I recommend them to anyone learning these concepts.
- GitHub - @ArinzeGit
- Frontend Mentor - @ArinzeGit
- LinkedIn - @Dennings-Owoh
- Instagram - @_.arinze._
- Twitter - @Arinze98433402