On this very special day, I decided to do not one, but two exercises in a single day! Helps me give me a kind of jogging for front-end stuff.
Photo by Alvan Lee on Unsplash
And today’s exercise is going to depend heavily on CSS so make sure your CSS skills are up to the mark!
In today’s exercise, we’re going to arrange 5 archons from a game, Genshin Impact [played it a lot in the past] in a grid-like fashion. When we move our mouse over an image, it’ll immediately show some additional text.
Our final image will look like this :
First, we’ll create the usual stuff with our boilerplate. Next, we add in a <div>
[main panel], inside which are nested 5 other <div>
. 5 image panels for 5 archons [on the date I’m typing this, Mavuika hasn’t been released yet. Don’t blame me if I don’t have her design yet].
Agh, our page looks not-so-nice. Let’s fix it up with CSS, hmm?
Did you know that you can also have CSS styles as snippets? I didn’t knew this earlier, but now that I do, I don’t have to type out my frequently used styles every time and instead just slap them in my stylesheet.
One such snippet is this one for body
style :
"Retrieve body" :
{
"prefix": "bd",
"body" :
[
"@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');",
"",
"body",
"{",
" font-family: 'Open Sans', monospace;",
" font-size: 20px;",
" margin: 0;",
" padding: 0;",
"}"
],
"description": "Create body style"
}
Now we shall simply add the usual flex style. Then we go back to our page…
Fuck yeah! Now it looks sick. But where are the images?
We add the images using another style, background-image
. Along with the images, we shall add a linear-gradient
with its colours set to black [rgb(0, 0, 0)].
.image-five
{
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.9)), url("..\\images\\furina.png");
}
Our classes in the HTML page will look like this : flex and flex-column along with the image’s individual class.
<div class="image image-five flex flex-column">
<p class="header-text quattrocento">FONTAINE</p>
<p class="displayed-text cinzel">Animula Choragi</p>
<p class="footer-text quattrocento">FURINA</p>
</div>
Not only are the images unevenly sized, there’s also a lack of sepia-ness in them…
This is when we introduce another class called before-change
. We change the height of our image to 50vh [that’s how you get that square-box-like look] and add a slightly sepia filter.
.before-change
{
height: 50vh;
transition: all 0.8s ease;
filter:sepia(10);
}
.after-change
{
height: 100vh;
transition: all 0.8s ease;
filter:brightness(2);
}
Also define in another class called after-change
. We’ll need it soon when we animate the page.
The page looks splendid! Now let’s animate it using JS.
First, select the images using querySelectorAll()
.
Then add in a for-each loop that adds an event listener [triggering upon click]. This listener will call a function that you’ll soon define.
panels.forEach(image => image.addEventListener('click', toggleClass));
Yep. Now define a function that takes event
as its argument [this means image will go in with the function]. In this function, assign a variable the value of event.target
.
function toggleClass(event)
{
let element = event.target;
element.classList.toggle('after-change');
element.classList.toggle('before-change');
}
What are we doing here? We simply toggle the two classes, before-change
and after-change
on and off when we click the image.
The final video can be fetched from day-five folder in assets. The folder containing it is named ‘video’.
Welcome back to today’s show where we mess around with CSS variables [please not the Sims version of it] using our shiny new tool, JS.
We’ll be using this painting, titled ‘The Champion’ painted by Sir Charles Lock Eastlake in 1824, for today’s exercise.
Photo by Birmingham Museums Trust on Unsplash
We build our HTML file using the boilerplate we’d defined earlier in our previous tutorial. Then we add in 3 <label>
elements with their respective <input>
elements.
<label for="spacing">Spacing:</label>
<input type="range" name="spacing" min="1" max="20" value="1" data-sizing="rem">
<label for="blur">Blur: </label>
<input type="range" name="blur" min="0" max="5" value="1" data-sizing="rem">
<label for="base">Background: </label>
<input type="color" name="base" value="#CC7722">
Let’s understand what’s at hand :
type
: Indicates the type of input we’re receivingmin
: Minimum valuemax
: Maximum valuevalue
: Increment / Decrement by what valuedata-sizing
: Unit used for valuesYou can safely ignore the lack of placeholder
attribute error given by HTML.
Now here’s where we take some real care :
:root
{
/* variables */
--blur: 1rem;
--spacing: 1rem;
--base: #CC7722;
/* styles */
font-size: 20px;
}
These are the variables defined in the root
part of CSS [note: root
= <html>
].
Then we use it in our styles :
.property
{
padding: var(--spacing);
background: var(--base);
filter: blur(var(--blur));
}
Let’s add a heading on top that has the same colour as the painting’s border.
Now let’s update the CSS variables with JS so they change with input.
First, we select all the <input>
elements inside the <div>
:
let input = document.querySelectorAll('.controls>input');
Next, we define a function that takes element as an argument.
We assign a variable the value of element.dataset.sizing || ""
[data-sizing
attribute in <input>
-> dataset.sizing
]. This means that we get the sizing unit for our further operations.
Then we use setProperty
on the document itself [remember, root
= <html>
= document].
document.documentElement.style.setProperty("--" + element.name, element.value + suffixValue);
What we’re doing here is : setting up the --variableName : value
format [or syntax] we’d do in :root
in CSS. This one will receive the custom values we’d pass to it as input.
To pass the said input, we use a for-each loop. Inside it, we call the function with input, then add an event listener to call it when we move the buttons in the page :
input.forEach((input) =>
{
updateVar(input);
input.addEventListener("input", () => updateVar(input));
});
And voila!
[The video showcasing this website, as well as the source code is available in the repository].
Welcome back to the 3rd day of the challenge! My exams have finally ended for now and this means I’ve enough free time to focus on side-projects such as this. Thinking of doing a piano-based keyboard-tapping [based on previous day’s exercise] soon. Anyways, today we’re gonna tackle another problem : building a clock.
Photo by Adrien Robert on Unsplash
Let’s build a simple analog clock and link to current time using JS. This means the clock is going to run in real-time [no static!]. This clock will also have the appropriate Roman numeral assigned to each hour.
Last exercise, I must’ve told you about the !
snippet. If possible, review that part here.
What if I told you that you can edit the snippet and save yourself some work on adding <div class="container">
, stylesheet, etc.?
"HTML Boilerplate":
{
"prefix": "!",
"body":
[
"<!DOCTYPE html>",
"<html lang=\"en\">",
"<head>",
" <meta charset=\"UTF-8\">",
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
" <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">",
" <title>${1:Document}</title>",
" <link rel=\"stylesheet\" href=\"\">",
"</head>",
"<body>",
" <div class=\"container\">",
" ${0}",
" </div>",
" <script src=\"\" defer></script>",
"</body>",
"</html>"
],
"description": "HTML Boilerplate"
}
Simple, follow these steps :
ctrl+shift+p
to get the command palette. If not, go to View and then click Command Palette.html.json
. Again hit enter.Now let’s get back to business.
<div class="center clock round">
<div class="clock-face round">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand sec-hand"></div>
</div>
</div>
With some CSS magic, we can make our clock look like this :
Get the CSS file for this website here!
Let’s do something extra - adding Roman numerals to indicate the hour of the day. First, add <div>
s for each number inside the HTML file.
<!--...-->
<div class="clock-face round">
<div class="roman-num">
<div class="number" style="--i:9;">I</div>
<div class="number" style="--i:10;">II</div>
<!--...-->
<div class="number" style="--i:8;">XII</div>
</div>
</div>
<!--...-->
Okay, why this unusual ordering? Why would the number I have the style for number IX and so on?
This is due to how transform
works :
.roman-num
{
top: 50%;
left: 2%;
}
.number
{
color:rgb(129, 123, 112);
font-weight: bold;
position: absolute;
width: 2rem;
height: 2rem;
transform: rotate(calc(var(--i) * 30deg)) translate(8rem) rotate(calc(var(--i) * -30deg));
}
So, when we pass a value of 9 to our variable --i
, it translates into this :
transform: rotate(calc(270deg)) translate(8rem) rotate(calc(270deg));
/* 9 * 30deg = 270deg */
270 degrees will mean the number is placed at the top [when starting from where IX would be]. Given the value changes in the variable, it means the numbers are placed at an interval of 30 degrees.
translate
here simply means that the numbers are thrown out to the edge of the clock’s face from their original position in the center.
Now let’s update the clock’s time using JS.
I am back after finally getting a website to post on [and after trying and switching from at least 3 themes due to various reasons]. Anyways, thanks to Hyde, we shall now focus on day one’s [our day two] challenge.
Photo by Gabriel Barletta on Unsplash.
Wonder why the very first day of this challenge comes after the fourth day? It’s because I’m following up from The Odin Project. I assure you that from hereon, the challenge will be in the usual order [barring the 4th day, of course].
Source for those who are curious : Drum Kit - Wes Bos
Tech used : JS DOM
Today we’re building a drum-kit. The cover image of this post shows one as an example in case you don’t know what a drum-kit is.
Our drum-kit site will do the following things when you press one of the displayed keys :
We’ll use the boilerplate provided by VSCODE by pressing !
and hitting enter. Then we attach the stylesheet and external JS.
After that, we’re creating a <div>
with a set of <div>
nested inside it.
Now we need to attach the audio files to our elements. For this, we’ll be using this website to get the key-codes for our letters.
Let’s take a look at the code for one of our keys:
<div data-key="KeyA" class="key">
<kbd>A</kbd>
<span class="sound-info">boom</span>
</div>
Normally, we’d place the <audio>
tag inside the <div>
and then try to work with the button. This usually won’t work. So, what I’m doing here is to create my own attribute [like a DIY attribute] named key
and use that alongside this :
<audio data-key="KeyA" src="day-one\boom.wav"></audio>
This is helpful for linking events using JS [using our class here, actually], which we’ll see soon.
The video must’ve shown the attribute
data-key=65
I presume? I’m sorry, but that’s depreciated. The best way to get keys for JS DOM is to useKey
alongside the key name.
There are 2 ways to do the CSS for this page.
One is to add the styles to each element using their class selector. Very simple to work with.
The other is to have many tiny class-selectors, each serving a purpose. Makes the code modular. This method is usually preferred in web dev [this is why you see a hundred different classes for an element when you open up inspect element].
<div data-key="KeyA" class="key flex flex-column box padding">
<kbd>A</kbd>
<span class="sound-info smaller-font">BOOM</span>
</div>
Ultimately, it’s your choice - bundle ‘em up into one big class, or split into many tiny classes. Both are okay.
Makes the displayed key bigger [i.e. it pops up with a jig] and applies a border around it.
This effect can be done using a CSS class. JS DOM will add this class to the key the moment the key is pressed. Here we can define border stuff, box-shadows, etc.
The key has a class as well. It has this transition style which enables this animation.
/* before transition */
.box
{
transition:all 0.05s;
color: white;
border: 0.1rem solid whitesmoke;
background: rgb(41,23,9);
background: linear-gradient(180deg, rgba(41,23,9,1) 0%, rgba(36,29,43,0.10452843246673671) 100%);
}
/* during transition */
.trans
{
transform: scale(1.3);
border-width: 0.2rem;
background: rgb(164, 147, 133);
background: linear-gradient(180deg, rgba(41,23,9,1) 20%, rgba(36,29,43,0.10452843246673671) 80%);
}
Now if you’re wondering what I’ve changed, I’ve :
transform
style that will make the boxes grow 1.3x their OG size.transition:all
makes the every element coming under the selector get the transition effect.
If you’re using external JS, ensure that your
<script>
tag has adefer
attribute in it. It ensures your scripts are loaded AFTER the html is parsed.
We’ll focus on listening to a key-down event [when user presses down a key in their keyboard].
We already know that the keys in our keyboard have key-codes assigned to each.
function addAudioWhenKeyDown(e)
{
console.log(e);
}
window.addEventListener('keydown', addAudioWhenKeyDown);
Using this, we can get the key and key-code from the console tab.
function addAudioWhenKeyDown(e)
{
let audio = document.querySelector(`audio[data-key=${e.code}]`);
console.log(audio);
audio.currentTime = 0;
audio.play();
}
e.keyCode
is depreciated. Better usee.code
instead.
Now our audio file are playing smoothly! We’ve added audio.currentTime
so that when you press the key multiple times, the audio rewinds back from the beginning and plays as many times instead of delaying.
At times, you may get null
along with a TypeError
. This is because that key doesn’t have an audio file assigned to it! To prevent that unnecessary message, add if (!audio) return;
to your function definition.
function addAudioWhenKeyDown(e)
{
//...
let key = document.querySelector(`.key[data-key="${e.code}"]`);
//...
console.log(key);
key.classList.add('trans');
}
//<div class="key flex flex-column box padding" data-key="KeyC">
Our transition effect is working well. However, there is a problem - we can’t revert back to normal without refreshing the page.
So, we need to add yet another event listener to remove the class from the keys :
window.addEventListener('keyup', removeTransitionEffect);
function removeTransitionEffect(e)
{
let keyDone = document.querySelector(`.key[data-key="${e.code}"]`);
keyDone.classList.remove('trans');
}
Background image by Aleksandr Popov from Unsplash
Aaaand we’re done! The files are enclosed in the repository, and thank you for reading till the end! See ya next time with a brand new walkthrough.