Giter Site home page Giter Site logo

phuocng / frontend-tips Goto Github PK

View Code? Open in Web Editor NEW
613.0 9.0 52.0 15.57 MB

Super tiny, quick tips, tricks and best practices of front-end development

Home Page: https://phuoc.ng/collection/tips

License: MIT License

MDX 100.00%
front-end front-end-development html css javascript developer-tools tips-and-tricks best-practices eleventy

frontend-tips's Introduction

Front-end Tips

A series of super tiny, quick tips, tricks and best practices of front-end development.

The series cover different topics:

  • CSS
  • HTML
  • JavaScript
  • TypeScript
  • Browser developer tools

Contributing

Pull requests are welcomed. To submit your favorite tip, please create a markdown file, and put it in the contents folder. The content of markdown file has to look like

---
category: ___
created: '___'
tags: ___
title: ___
---

The content of post
  • category: Can be one of Tip, Trick or Practice
  • created: The date that post is created
  • tags: The list of topic(s), separated by a comma
  • title: Must match with the file name

Here is an example.

About

This project is developed by Nguyen Huu Phuoc. I love building products and sharing knowledge.

Be my friend on

frontend-tips's People

Contributors

akulsr0 avatar andrew-walker91 avatar apollorisky avatar dnrm avatar dylankenneally avatar kittygiraudel avatar masteryi2333 avatar phuocng avatar pixelt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

frontend-tips's Issues

Remove a property from an object with spread operator

We can use the ES6 spread operator to remove a property from an object:

const { name, ...rest } = { name: 'Foo', age: 20 };

console.log(name);      // 'Foo'
console.log(rest);      // { age: '20' }

It's also possible to remove a dynamic property:

const property = 'name';
const { [property]: value, ...rest } = { name: 'Foo', age: 20 };

console.log(value);     // 'Foo'
console.log(rest);      // { age: '20' }

[Good practice] Trim the spaces before parsing the number

Both Number() and parseInt accept the spaces in input. But be aware that you could get different result when passing a value with spaces as following:

parseInt('   5   ');    // 5
parseInt('12 345');     // 12, not 12345

To avoid the similar situations, you should remove all spaces before parsing:

parseInt(value.replace(/s+/g, ''), 10);

[Fun] Why does 'hello'.charAt(true) return e?

The charAt(index) method will try to convert the index to the number first. Since Number(true) === 1, charAt(true) will returns the character at the one index position, i.e, the second character.

Get characters of a string

[first, ...rest] = 'Hello'
first = 'H'
rest = ['e', 'l', 'l', 'o'] 

We can use it to capitalize a string

capitalize = ([first, ...rest]) => `${first.toUpperCase()}${rest.join('')}`
decapitalize = ([first, ...rest]) => `${first.toLowerCase()}${rest.join('')}`

[Good practice] Don't add custom methods to primitive objects

It is not recommended to add a custom method to primitive objects such as Array, Boolean, Number, String, etc. Since for ... in statement loops over the enumerable properties, it will include new methods which are added to the prototype.

Array.prototype.isEmpty = function() { 
    return this.length = 0;
}

const a = ['cat', 'dog', 'mouse'];
for (let i in a) {
    console.log(i);     // '0', '1', '2', 'isEmpty'
}

[Good practice] Use string literals for the enum values

If you don't set the values for enum, they will be set to incremental numbers by default.
Let's say that we have the following enum:

enum Theme {
    DEFAULT,
    LIGHT,
    DARK,
}

So Theme.DEFAULT, Theme.LIGHT and Theme.DARK will take the value of 0, 1, 2, respectively. It is more hard to debug:

console.log(Theme.DARK);    // 2

Even if we set the number for enum values, it's still possible for us to set an invalid value for a variable whose type is the enum:

enum Theme {
    DEFAULT = 0,
    LIGHT = 1,
    DARK = 2,
}

// TypeScript doesn't throw errors
const theme: Theme.DEFAULT = 3;

Due to these reasons, it's advised to use string literals for the enum values. The Theme enum should look like as follow:

enum Theme {
    DEFAULT = 'Default',
    LIGHT = 'Light',
    DARK = 'Dark',
}

console.log(Theme.DARK);                // 'Dark'
let theme: Theme.DEFAULT = 'Default';   // ERROR

Use the template literal syntax in ES6

You can use the template literal syntax in ES6 to get rid of escaping quote. For example:

// Instead of
const message = 'It\'s a message';

// We can do this which is more convenient
const message = `It's a message`;

[Good practice] Always pass the radix to parseInt

The parseInt method takes two parameters:

parseInt(value, radix);

The second parameter specifies the current numeral system. In the case it's not specified, then it will be set automatically based on the value.
If the value starts with 0x or 0X, then the radix is 16 (hexadecimal)
In other cases, the radix is 10 (decimal).
In the older versions of JavaScript, if the string starts with 0 then the radix is set as 8 (octal).

parseInt('0xF');        // 15
parseInt('0XF');        // 15
parseInt('0xF', 16);    // 15

parseInt('0xF', 10);    // 0

Since the method could be implemented differently in different versions of JavaScript and browsers, it's recommended to pass the radix number.

[Tip] wbr element

A browser might break a long text at unexpected places. For example, the specific path (`/this/is/.../folder`) in the following text
is placed at the second line:
~~~
┌───────────────────────────────────────────────────────┐
| Copy file to the folder: |
| /this/is/a/very/long/path/to/the/destination/folder |
└───────────────────────────────────────────────────────┘
~~~
To prevent this behavior, HTML5 provides the `` element. It stands for Word Break Opportunity, and is used to specify the
positions that a line break would be created.
Getting back to the example above. If we use `` elements right before each path separator (`/`) as follow:
~~~ html
Copy your file to the folder:
/this
/is
/a
...
/destination
/folder
~~~
The browser will break the paths in between the directory names:
~~~
┌───────────────────────────────────────────────────────┐
| Copy your file to the folder: /this/is/a/very/long |
| /path/to/the/destination/folder |
└───────────────────────────────────────────────────────┘
~~~
Note that `` element is not supported in IE 11 and earlier versions.

Avoid to use colons (:) and periods (.) in id attribute

According to the HTML specifications,
a valid id can consist of almost characters except ASCII whitespace.
Assume that we have an element representing an user's email address:
~~~ html


~~~
In order to access the element, the `getElementById()` method accepts all of three ways passing the `id`:
~~~ javascript
// They return the same element
document.getElementById('user.email')
document.getElementById('user\.email')
document.getElementById('user\\.email')
~~~
But these methods return different results if you are using jQuery library:
~~~ javascript
// Function // Returned element
$('#user.email') //

$('#user\.email') //

$('#user\\.email') //

~~~
As you see, the first two methods will find an element with `id` of `user` and has `email` class.
In order to get the correct element, we have to escape the `id` using double backslashes (`\`).
It also happens if we use the same value in CSS:
~~~ css
#user.email {
...
}
~~~
All the styles declared within `#user.email { ... }` has effect on the element with `id` of `user` and has the `email` class.
The styles aren't applied to element with `id` of `user.email`. To define the styles for our element, we have to escape the selector.
But this time, it requires a single backslash only:
~~~ css
#user\.email {
...
}
~~~
Avoid using the special characters in the `id` and `class` attributes will help us get rid of the confusion and errors above.
If it's not possible to get rid of colons and periods (for example, the `id` attribute is generated by the server side),
then you can use the single backslash as above, or use the attribute selector.
Note that it has a lower specificity than the `id` selector:
~~~ css
[id="user.email"] {
...
}
~~~

[Tip] Convert string to number

Instead of using the Number() constructor to convert a string to number, you can use the + operator:

+'010';     // 10
+'2e1';     // 20
+'0xF';     // 15

Use an underscore to name unused argument

You can use an underscore to name the argument which is not used in an arrow function. It makes the code more readable.

// No arguments
const noop = _ => {};

const range = (min, max) => Array(max - min + 1).fill(0).map((_, i) => min + i);

Track the focused element with Chrome DevTools

Assume that you want to test the keyboard accessibility in your website.

There's a case that the pressing the Tab key jumps to a particular element which is invisible in the viewport.

Chrome DevTools provides the ability of tracking the focused element.
* Open the Console
* Click the eye icon which is located at the right of the Filter box to create a live expression
* Type `document.activeElement`
This live expression will represent the active element which has the focus currently. You can right click on the expression's
result and then choose Reveal in Elements panel to inspect the focused element.

image

A note on preventing default handler with jQuery

If you're using jQuery to manage the events, then you're able to use return false within the event handler:

$(element).on('click', function(e) {
    return false;
});

Before returning the value of false, the handler would do something else. The problem is that if there's any runtime error occurring in the handler, we will not reach the return false statement at the end.

In that case, the default behavior will be taken:

$(element).on('click', function(e) {
    // Do something here, but if there's error at runtime
    // ...
    return false;
});

We can avoid this situation by using the preventDefault method before performing any custom handler:

$(element).on('click', function(e) {
    e.preventDefault();

    // Do something here
    // The default behavior is prevented regardless errors at runtime
    // ...
});

[Tip] Put + at the beginning of function

Usually, we can invoke a function by using the form of Immediately Invoked Function Expression (IIFE).

(function(a, b) {
    return a + b;
})(4, 2);

// 6

Do you know that we get the same result if we omit the parentheses and put + at the beginning as follow:

+function(a, b) {
    return a + b;
}(4, 2)

// 6

It works because putting + at the beginning of function declaration will turn it to an expression, and passing the parameters with () at the end will invoke the expression.
It is rare to see that code in development, but it is used in the minifications to save the file size.
In addition to +, you can use other operators such as -, !, ~ and void in the similar way to invoke a function:

-function() { ... }();
!function() { ... }();
~function() { ... }();
void function() { ... }();

Note that the return value could be different from the original function, for example:

!function() { return false; }();     // true

Merge different arrays

You can use ES6 spread operator to merge different arrays into one:

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [7, 8, 9];

const final = [...a, ...b, ...c];   // [1, 2, 3, 4, 5, 6, 7, 8, 9]

The spread operator is handy if we use the push method as well:

const a = [1, 2, 3];
const b = [4, 5, 6];

a.push(...b);
a;              // [1, 2, 3, 4, 5, 6]

[Tip] Override the behavior of instanceof

instanceof doesn't work for primitive types.
If you want to use instanceof all the time, then you can override the behavior of instanceof by implementing a static method with the key of Symbol.hasInstance.
In the following code, we create a class called PrimitiveNumber that checks if a value is a number:

class PrimitiveNumber {
    static [Symbol.hasInstance](value) {
        return typeof value === 'number';
    }
}

12345 instanceof PrimitiveNumber;           // true
'helloworld' instanceof PrimitiveNumber;    // false

Indicate img elements that don't have alt attribute

Give a red outline to any img having a missing or blank alt attribute:

img:not([alt]),
img[alt=""] {
    outline: 8px solid red;
}

If you are using Visual Studio Code, you can install the webhint extension. It will automatically detect the issue and show the details when you hover on the element.

image

Wrap function body in parentheses

If the inline arrow function consists of the <, <=, > or >= operator, it is advised to wrap the function body in parentheses.
Looking at the two versions below, it is easy for the first variant to cause a misleading.

// Bad
const compareToZero = a => a <= 0 ? 0 : a;

// Good
const compareToZero = a => (a <= 0 ? 0 : a);

Visualize elements on page with outline

The outline property is useful when you want to visualize elements on the page. In the following sample code, we iterate over all the elements and set the outline property with a random hex color:

[].forEach.call(
    document.querySelectorAll('*'),
    ele => {
        const color = `#${Math.random().toString(16).slice(2, 8).padEnd(6, '0')}`;
        ele.style.outline = `1px solid ${color}`;
    }
);

Of course, you will need an opposite command to reset the outline property:

[].forEach.call(
    document.querySelectorAll('*'),
    ele => ele.style.removeProperty('outline')
);

You can change the selector from * to whatever you want to match the set of particular elements, for example:

// Set the outline for links only
[].forEach.call(
    document.querySelectorAll('a'),
    ...
);

Prefix class name with `js-`

Have you ever seen a class name starting with js-?
If the answer is not, then you can visit Github and see the source of generated HTML. There are bunch of elements whose class are prefixed with js- such as:

<meta class="js-ga-set" name="userId" content="...">
<meta class="js-ga-set" name="dimension1" content="...">

They are often used to manage the list of elements that we don't want to set id for (dynamic elements, for example). In these cases, we use the document.querySelectorAll('js-xxx') method to retrieve the elements list.

In the other words, the js- classes don't define the styles, but for managing the elements in JavaScript instead. That's why they are prefixed with js-. Follow this naming convention is helpful if you're working in a team. Other engineers will be aware of the class name, and don't remove them when refactoring the page.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.