This project is solely for learning purposes. I take no any responsibility or liability for the accuracy, completeness, or usefulness of any information provided in this project. You should not use it as a reference for creating your project.
I am currently no longer working on this project.
Welcome to the README.md
of this repo! The purpose of creating this project is to practice using modern CSS such as clamp()
, calc()
, CSS logical properties, and much more.
In this file I'm going to tell you everything, starting from tools that I used, and much more.
That's it for the introduction and happy reading!
- View the optimal layout for the site depending on their device's screen size
- See hover states for all interactive elements on the page
- See error states when the contact form is submitted if:
- The Phone Number and/or Email Address fields are empty
- The Email Address is not formatted correctly
- See visible focus states for interactive elements when navigating by keyboard
- Understand and be able to navigate page content while using assistive technology
- Bonus: See a live countdown timer that ticks down every second
- Bonus: See a custom-styled select form control in the sign-up form
- HTML Semantic Tags
- BEM (Block, Element, Modifier)
- Sass
- JavaScript
- CSS Flexbox
- CSS Grid
- CSS Logical Properties
- Fluid Typography
- Fluid Space
- Mobile-first workflow
HTML, CSS, and JavaScript are three different things. As a developer, I should not mix them as much as possible.
Learn more about separation of concerns at Wikipedia
I am going to use the following HTML markup to show you how we can apply that in practice.
<div class="form__wrapper">
<label
for="email-input"
id="email-label"
class="form__label"
hidden
>
Email Address
</label>
<input
type="email"
id="email-input"
class="form__input js-input"
name="email"
placeholder="Email Address"
required
aria-labelledby="email-label"
aria-describedby="email-alert"
data-id="email"
/>
<p
id="email-alert"
class="js-alert"
aria-live="polite"
hidden
data-id="email"
></p>
</div>
There are a lot of things going on in this HTML markup. So, let me explain it.
First, let's focus only on the HTML markup. This is where the accessibility is happening.
<div>
<label
for="email-input"
id="email-label"
hidden
>
Email Address
</label>
<input
type="email"
id="email-input"
name="email"
placeholder="Email Address"
required
aria-labelledby="email-label"
aria-describedby="email-alert"
/>
<p
id="email-alert"
aria-live="polite"
hidden
></p>
</div>
There are five important things here.
- The input has a hidden label.
- Correct
type
for theinput
. - The
p
for the input error message is linked witharia-describedby
. - The
p
also hasaria-live
attribute to make screen readers pronounce it when the error message is in thep
. - The
p
is hidden since the error message won't be visible. So, when the input is invalid state thehidden
will be replaced bysr-only
class.
Second, I should be able to focus on the same HTML markup but with "CSS in mind". So, I should only care about styling.
Don't use aria-live
as the selector because it has nothing to do with CSS. It's for accessibility.
Don't make the CSS selector like the structure of the HTML. For example, div > label
. It's because if I decided to have another div
that wrapped the label
then, the styling will be broken.
So, I need to have class only for styling purposes. This way, if I change the HTML, the styling won't get affected.
<div class="form__wrapper">
<label>
Email Address
</label>
<input class="form__input" />
<p></p>
</div>
For the styling, I only need to care about the div
and the input
. The label
is hidden and so is the p
.
Then, when the input is in an invalid state, there should be is-invalid
class.
<input class="form__input is-invalid" />
Lastly, for JavaScript, I will use js-
class selectors to grab the DOM elements. This way, the CSS selectors and the JavaScript selectors are separated.
<div>
<label>
Email Address
</label>
<input class="js-input" data-id="email" />
<p data-id="email"></p>
</div>
I use data-id
to match the input
and the associated error message.
Of course, I can do the following inside to select the error message the JavaScript.
const handleAlert = (message, input) => {
const inputParentElement = input.parentElement;
const alert = inputParentElement.querySelector(".js-alert");
showAlert(message, alert, input);
}
But, this JavaScript code is always assumes that the alert element has the same parent element as the input
. So, if in the future the error message is not having the same parent element. Then, I need to refactor my JavaScript.
So, by using data-id
, I don't need to worry about the HTML structure. The error element can be everywhere and it will always be matching with the input
.
This is how I apply the separation of concerns principle. 😎
- Andy Bell – Be the browser’s mentor, not its micromanager - YouTube - This video helped me understand the fluid type and fluid space. This approach helped reduce the amount of media queries by using modern CSS such as
clamp()
,calc()
, and much more! - Stephanie Eeckles - Scaling CSS Layout Beyond Pixels - YouTube - This video helped me understand how to use modern CSS such as using
clamp()
, CSS Grid (minmax()
,auto-fit
, etc), and much more! - Utopia - This a great calculator that helped generating
clamp()
functions. It helped me creating fluid space and fluid typography easily.
See the documentation.