Below, you will find some discussion of ways to customize certain HTML elements. Many of the elements you need to design for your app share properties discussed below. Keep in mind that these are just examples.
Instead of using the code explained below as is, please design your own custom widgets or controls. It is difficult for me to give you points for my own design and code.
Here we’ll play with a plain old text input field. There are several of those as well in the app. To start with, a text input looks like this.
<form action="#" autocomplete="off" id="textInput"> <fieldset> <input id="first" type="text" name="first" required> <label for="first">First Name</label> </fieldset> </form>
Note that I have included a <form> tag and a <fieldset> tag. These are not absolutely necessary to simply show the input. But if it were to be used, the input would need to be inside a form. You know this already. And we will use the fieldset for some fancy transitions later. Stay tuned!
The code above, as default, looks like this.
Now we can customize this thing. Let’s start with simple changes. The label is a just a text container. You can apply to it any property that affects typography: font-family, size, color, etc. The text box itself, the input, is like a block element, it has: border, background, box-shadow, etc. Notice that the label is after the input. This is because of the way we will use it. You could do it otherwise.
So let’s make the label blue (my default text colour on this page is grey). And let’s place it right below the field instead of on its right. Also, let’s set the field’s border so it is just a line on the bottom of the field instead of a box. More like a print form. Finally, let’s eliminate the border around the fieldset. You’ll need to place this CSS code inside a style tag to try it out.
Note that I did not change the width of the input. It is a bit too small for a real text field. In your app, you should consider the size of fields. But it does not matter here for our discussion.
#textInput fieldset { border: none; } #textInput label { color: #339; display: block; } #first { outline: none; border: none; border-bottom: solid #339 2px; }
With the code above applied, it looks like this.
Now try to click on the field to type in it. You see how the colour, the border, etc. change? This is done with a transition between states in CSS. The code looks like this. (I’ve just put the two rules for the input field. This replaces the two rules with the same selector from the previous code block. Do not duplicate rules.)
#first { outline: none; border: none; border-bottom: solid #339 2px; transition: all 0.5s; } #first:focus { /*this is the focus state*/ border-bottom: solid green 2px; background: lightgreen; }
Let do something more fancy. We’ll put the label ‘inside’ the field, so it looks like a placeholder. And when you give the focus to the field, the label moves to the top and lets you write what you want.
This sounds complicated, but it is not that bad. The CSS is a little bit more elaborate. Here it is. I will explain it below. Again, the rules here that have selectors that already exist should not be duplicated. They should replace what you have already. You need to add the new rules.
#textInput fieldset { border: none; position: relative; } #textInput label { position: absolute; top: 1em; color: #339; display: block; transform-origin: left; transition: all 0.5s ease; } #first { outline: none; border: none; border-bottom: solid #339 2px; margin-top: 1em; transition: all 0.5s; } #first:focus, #first:valid { border-bottom: solid green 2px; background: lightgreen; } #first:focus ~ label, #first:valid ~ label { top: 0px; transform: scale(0.8, 0.8); color: green; }
The first odd thing you will notice here is that we set the position: relative; for the fieldset. This is to allow us to then specify the absolute position of the label so we can animate the label’s position.
Next up, we set the position: obsolute; for the label, like I just mentioned. Then we position it so it appears inside the field: top is the property that positions an element from the top. We also set the transform-origin which determines from which side it will scale (we’ll get to that). And of course, we need to set a transition property so it animates the transition between the states.
The input #first is basically like it was in the previous step. The focus state of the input also remains the same. But you will notice that I have added a second selector: #first:valid to the rule. This determines the properties of the input when it has a value in it. We don’t want the label to move back into the field after the user has entered their value.
The last rule is a new one. And it is probably a selector you have never used. The ~ connector selects siblings: elements that have the same parent. This is why we need the label tag after the input in the HTML, so we can select it using this selector type. So #first:focus ~ label means: get the label element (tag selector) that is a sibling of the #first element, when this one has the :focus (when the keyboard insertion point is in it). So what happens to the label when the input gets the focus? It moves to top:0px; (no longer inside the field, but above it). We also scale it so it appears smaller. And we make it green, like the colour of the field on focus.
I want you to notice how the colours in the examples I provide are similar. Notice how the stand states are all using #339 blue. Notice how the active states use #393 green. And most of the greys are #ccc. This is not a chance thing, it is not random. This is a decision, it is design. This makes the text fields and the buttons part of the same visual family, they use the same visual language.
I could have used other features to further emphasize this visual language: stroke thickness, box shape, line style, relative sizes, etc. It is part of your mandate to design every element of the interface as members of a system. I used colour for this here.
So let’s talk about colour. How do you determine how many colours your need for a project? What is the purpose of colour? I am not talking about which colour to choose, I am talking about the use of colours in a product. Which colour you use depends on different things: mood, audience, branding, etc. But how many colours and how you use colour is determined by some very specific needs of the product.
We use colours for a single purpose in design: to distinguish, or if you want, to create contrast.
You need different colours to categorise the content. So the number of colours you use in a product is determined by the number of categories of things you have. That is it.
Let’s say you want to design a letter. A letter will be a sheet of paper and some characters printed or written on it. 2 things = 2 colours. Typically, these will be white (for the paper), and black (for the ink). But, if you are fancy, they could be light beige (for the paper) and dark blue (for the ink). The thing remains though: two categories of things therefore two colours. Contrast. This is true for all products you design.
There are other ways of creating contrast (shape, texture, size, etc.), so you don’t necessarily need one colour for each category of things. But always use colours with purpose.
So to determine the colours you will use for this project, figure out the categories of things you will have to use colours for: different types of buttons, a hierarchy of labels, fields of different functions, etc. Once you know how you intend to use colours, you can decide which colours you will use.
An icon usually refers to a small illustration. It is often used instead of words on controls. Typical icons you encounter include:
(I have used a free icon library called Friconix to provide these examples. If you want, you can start with an icon from a library, but you need to add animation and other properties, so be careful what you use. Believe me, it is better if you draw it yourself. Plus I only ask for 2, so…)
More elaborate icons are also used to identify apps: the blue ‘Ps in a square’ of Photoshop (the icon was much more detailed before, look it up), Chrome’s colourful poké ball, etc. Emojis are icons too. Icons are everywhere.
This is an example of an icon drawn in SVG. If it were used in an app, it would probably be smaller, but I want to make this presentation clear (hint). This icon has three states: stand, hover, and click. If you put your mouse over it, you will have a surprise. And if you click it, you will see something else happen. Let’s see how it’s done.
This is the SVG code for this icon. You can also look at the source of this page… You don’t have to worry about the details, but notice the IDs of the two groups (<g> tag): #smoke and #house. We’ll use these in the code later.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" xml:space="preserve"> <g id="smoke"> <path class="st0" d="M129.5,66.5c0,0-4-9,1-22s3-26.6,0-29.3c-2.2-2,11.2,8.2,13.5,28.1c0.8,6.7,0.2,14.4-2.5,23.2H129.5z"/> </g> <g id="house"> <polygon class="st1" points="146.5,104.7 146.5,66.5 124.5,66.5 124.5,86.8 99.5,66.5 24.5,127.5 49.8,127.5 49.4,180 87,180 87,143.5 112,143.5 112,180 148.7,180 149.1,127.5 174.5,127.5"/> </g> </svg>
Alright, now let’s look at the states. You have probably figured out by now, that the states are often defined in CSS, using pseudo classes like :hover and :active. For this icon, we will use JavaScript (JS) as well to define the states. In fact, I designed this icon using an animation library other than GSAP that we used in the previous assignment. The transitions are animated in CSS, but the smoke flicker uses Anime.js. (More about this below.) I did this just to show you how to use another library. Something you need to get used to. Of course, you can use GSAP in your icons. Or you can also use no library at all and just animate the transitions using CSS. It’s your work.
Stand State
The stand state is just the drawing as is. But we need to hide the smoke. So the CSS looks like this. Notice that the opacity of the smoke path is 0 (zero). Both house and smoke have transitions setup, so when properties change, CSS will animate the transition.
Also notice that the selectors apply these properties to the object inside the group rather than to the group. In this case here, we want to manipulate the fill and other properties of the path and polygon. The group <g> elements have no such properties. So we need to manipulate the vector objects, not the groups.
#house polygon { fill:#FFF; stroke:#000; stroke-width:5; transition: all 0.2s; } #smoke path { fill:#CCC; stroke:#000; stroke-width:0; opacity: 0; transition: opacity 0.5s; }
Click State
I will talk about the click state first because it is less complicated and more familiar. The only thing is that the event trigger is managed by JS instead of CSS.
So what happens is that we change the value of the fill property of the house polygon from white to green. The JS code looks like this. (This code would need to be inside a <script> tag at the bottom of your HTML file to work.)
document.querySelector("#svgIcon").addEventListener("mousedown",function() { document.querySelector("#house polygon").style.fill = "#393"; }); document.querySelector("#svgIcon").addEventListener("mouseup",function() { document.querySelector("#house polygon").style.fill = "#FFF"; });
You notice right away that I do not use the click event. Why not? The thing is that I want to set the fill colour to green only when the mouse is down, when the user is cliking. And then, I want the colour to be back to white when the mouse is lifted. So I need to handle the mouse down event (to make the fill green) and then the mouse up event (to make it white again). If you want something like a like button, you can use the click event. Once the icon is clicked, it will remain as is. (Don’t forget the mandate though!)
So the first line selects the #svgIcon element, and attaches to it an eventListener for the mousedown event. When this event is triggered, we select the #house polygon element, and set its fill property to #393 (green).
The other event listener is similar, but it turns the fill white on the mouseup event.
Hover State
Now let’s handle the case when the mouse moves over the icon, the smoke animation appears. There are two thing happening here: a transition (the smoke appears) and an animation (the smoke moves around). The transition is achieved by changing the opacity of the smoke path. The animation, like mentioned above is done using the Anime.js library. So the trigger of the state change event is managed by JS.
The code looks like this. Notice the two separate parts.
//Animation let smokeAnim = anime.timeline({ autoplay: false, loop: true, duration: 8000, easing: "easeInOutQuint" }); smokeAnim.add({ targets: "#smoke path", d: [ { value: 'M142.8,63.5c0,0,4-9-1-22s-3-26.6,0-29.3c2.2-2-11.2,8.2-13.5,28.1c-0.8,6.7-0.2,14.4,2.5,23.2H142.8z'}, { value: 'M129.5,70.5c0,0-4-9,1-22s3-26.6,0-29.3c-2.2-2,11.2,8.2,13.5,28.1c0.8,6.7,0.2,14.4-2.5,23.2H129.5z'}, { value: 'M142.8,64c0,0,4-9-1-22s-3-26.6,0-29.3c2.2-2-11.2,8.2-13.5,28.1c-0.8,6.7-0.2,14.4,2.5,23.2H142.8z'}, { value: 'M129.5,66.5c0,0-4-9,1-22s3-26.6,0-29.3c-2.2-2,11.2,8.2,13.5,28.1c0.8,6.7,0.2,14.4-2.5,23.2H129.5z'}, ] }); //Transition document.querySelector("#svgIcon").addEventListener("mouseenter",function() { document.querySelector("#smoke path").style.opacity = "1"; smokeAnim.play(); }); document.querySelector("#svgIcon").addEventListener("mouseleave",function() { document.querySelector("#smoke path").style.opacity = "0"; smokeAnim.pause(); });
The first part is the animation. I will not get into too much details about Anime.js in this tutorial. Just notice that the variable reference to the animation is called smokeAnim.
Like I said above, you do not need to use a library for this assignment. And if you want, you can use the GSAP library you already know a little bit. I leave the Anime code there though if you are curious and would like to try it out. Imporant: Do not venture into this if you are struggling with code. An important feature of becoming a designer/creator is to know your limits. I include this here for the more advanced and curious among you. It is perfectly ok to ignore this part.
So focus on the second part: the transition. Here again we have two events: mouseenter and mouseout. These are triggered respectively when the mouse enters the vicinity of the element, and when it moves away from it. It is possible that you are already familiar with these two events, they are quite common.
On mouseenter the #svgIcon element, we select the #smoke path and set its opacity to 1. This renders it visible. Then we play the smokeAnim animation. This play() function comes from the Anime.js library.
On mouseleave now, we reverse this. We set the opacity of #smoke path back to 0 (hide it again), and we pause the smokeAnim.
Volà!
I hope these examples and tips were useful. I could give you tons of others, but there would be more words to read... haha.
Take what you need from this. Always keep in mind that you need to create your own product.
You can do this!