Frontend tips and tricks
transform: perspective(1px) ...
Unitless line heights are recommended due to the fact that child elements will inherit the raw number value, rather than the computed value. With this, child elements can compute their line heights based on their computed font size, rather than inheriting an arbitrary value from a parent that is more likely to need overriding.
line-height: 1.5;
* > *
selectorshttps://github.com/yannickcr/eslint-plugin-react/issues/1153
https://www.nngroup.com/articles/form-design-placeholders/
.ComponentAsBlock-layoutPropertyAsElement—boolAttributeAsModifier.is-state
Bad:
<div className="SomeBlock">
<div className="SomeBlock-someElement SomeBlock-someElement--someModifier SomeAnotherBlock">
<div className="SomeAnotherBlock-someElement">
</div>
</div>
</div>
.SomeBlock {
// Some block styles
&-someElement {}
// Some modifier styles
&--someModifier {}
}
Good:
<div className="SomeBlock SomeBlock--someModifier">
<div className="SomeBlock_someElement">
<div className="SomeAnotherBlock SomeAnotherBlock--someModifier">
<div className="SomeAnotherBlock_someElement">
</div>
</div>
</div>
</div>
// Some block styles
.SomeBlock {}
.SomeBlock_someElement {}
// Some modifier styles
.SomeBlock--someModifier {}
.SomeBlock--someModifier .SomeBlock_someElement {}
get method() {
return (async () => {
try {
let data = await service.call()
if(!data) throw Error('No data')
return {data};
} catch(e) {
return e;
}
})()
}
const choice = (opt) => {
const cases = {
foo: 'bar'
}
return cases[opt] || 'baz';
}
choice('foo') // bar
choice('bar') // baz
const createChoice = (cases, default) => opt => cases[opt] || default;
const choice = createChoice({
foo: 'bar'
}, 'baz')
choice('foo') // bar
choice('bar') // baz
RegEx: [\p{IsCyrillic}]+
const foo = () => {}
const bar = (foo => {
return (...args) => {
foo(...args);
// ...
};
})(foo);
input[type=submit] {
// box-sizing: border-box; // not work?
border: 1px solid transparent;
}
<img src="animation.mp4" />
const Foo = function (args) {
let options = args || {};
let i = options.start || 0;
const step = options.step || 1;
const enc = () => i+=step;
const dec = () => i-=step;
const state = () => i;
return Object.freeze({
constructor: Foo,
enc: enc,
dec: dec,
});
}
const Bar = function () {
let self = Foo.apply({},arguments);
const {set,state} = self;
const pow = times(() => set(state() * state()));
const root = times(() => set(Math.sqrt(state())));
return Object.freeze({
...self,
constructor: Bar,
pow,
root
})
}
reduce to*
let dest = reduce(src, toFoo, init)
filter where*
let dest = filter(src, whereFoo)
forEach * (action it self)
forEach(src, foo)
export default (React, Button) => {
'use strict';
return (props = {}) => {
let {title, ...rest} = props;
return <Button {...rest}>{title}</Button>
}
}
else
if (...) return ...;
return ...;
...rest
propsAlways destructorize pros into named properties, because of React principles
-<Foo {...rest} />
+<Foo bar={bar} />
Except decorators:
const MyInput ({ label, ...rest }) => <label>{label}<input {...rest}/></label>
sans-serif:
font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
monospace:
font-family: 'SFMono-Regular', 'SF Mono', 'Ubuntu Mono', Consolas, 'DejaVu Sans Mono', Menlo, monospace;
This solution is harmless and very useful. It is used by GitHub, Wordpress, Bootstrap, Medium, Ghost, etc.
The main reason for using "system" fonts is performance. Fonts are typically one of the largest/heaviest resources loaded on a website. If we can use a font already available on the user’s machine, we can completely eliminate the need to fetch this resource, making load times noticeably faster. The beauty of system fonts is that it matches what the current OS uses, so it can be a comfortable look.
-apple-system targets San Francisco in Safari (on Mac OS X and iOS), and it targets Neue Helvetica and Lucida Grande on older versions of Mac OS X. It properly selects between San Francisco Text and San Francisco Display depending on the text’s size. system-ui represents the default UI font on a given platform. BlinkMacSystemFont is the equivalent for Chrome on Mac OS X. Segoe UI targets Windows and Windows Phone. Roboto targets Android and newer Chrome OS. It is deliberately listed after Segoe UI so that if you’re an Android developer on Windows and have Roboto installed, Segoe UI will be used instead. The bottom line: It's truly the ultimate solution for any website/webapp in any OS.
(new CSSStyleSheet())
.replace('@import url("//fonts.googleapis.com/css2?family=Montserrat:wght@100&display=swap")')
.then((sheet) => {
sheet.replaceSync("body { font-family: 'Montserrat', sans-serif; }");
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
})
.catch(({ message }) => { console.warn(message); });
As a general rule, stopping event propagation should never be a solution to a problem.
https://css-tricks.com/dangers-stopping-event-propagation/
<link rel"preconnect" href="https://fonts.google.com" crossorigin>
Nested objects are difficult to support
Good:
const moo = {
fooBar: 1,
fooTar: 2,
}
Bad:
const moo = {
foo: {
bar: 1,
tar: 2,
}
}
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
Except these:
// Sometimes you only want an integer
const mix = 0xFFFFFFFF;
mix >>> 0; // converts to UInt32 2^32 will be rounded down (truncated, as in Math.floor) to the nearest integer. Numbers ≥ 2^32 are turned to 0. Numbers less than 0 will turn into a positive value (thanks to the magic of two's-complement representation).
mix | 0; // converts to Int32 0xFFFFFFFF | 0 = -1
WARN: Response may change after POST requests, so, need to pass some additional increment parameter to pass trough memoization. Cache-Control HTTP header already has caching mehanisms. Better to use debounce.
import memoizeOne from 'memoize-one';
const getCommands = memoizeOne(() => axios.get(`${url}/commands`))
f = async () => await Promise.resolve(1);
f = async () => Promise.resolve(1);
f = () => Promise.resolve(1);
f = () => ({ then: fn => fn(1) });
f().then(console.log) // 1
[...new Set(data.map(x => x.foo))]
Object.values(someObject).find(Boolean)
draw = () => {
document.body.innerHTML = (new Date()).toLocaleTimeString();
requestAnimationFrame(draw);
}
draw();
Object.prototype.toString.call(...)
array instanceof Array
Object.assign([], collection, {[key]: value});
const withDefaultValue = (defaultValue = null) => (target) => new Proxy(target, {
get: (target, prop) => prop in target
? target[name]
: defaultValue,
});
const IndexedArray = new Proxy(Array, {
construct(target, [args]) {
const index = new Map();
args.forEach(item => index.set[item.id, item]);
return new Proxy(new target(...args), {
get(arr, prop) {
switch (prop) {
case 'push': return item => {
index.set(item.id, item);
arr[prop].call(arr, item);
}
case 'findById': return index.get;
default: return arr[prop];
}
}
})
}
})
const foo = Object.freeze({});
const makes the variable binding immutable but it’s value can still be modified. Object.freeze() ignores the value modification to an object but there is no restriction on the binding.
Linking foo/foo.js to foo/index.js:
export * from './foo';
Exporting components from one file:
export { default as Foo } from './foo'
export { default as Bar } from './bar'
JSON.stringify(Object.fromEntries(formData));
('0000'+123).substr(-4)
is same as (''+123).padStart(4,'0')
'+0123456789876'.replace(/(..)?(...)?(...)?(...)?(...)?/, '$1 ($2) $3 $4 $5')
[a,b] = [b,a];
[/a/, /b/, /c/, /d/].find(r => r.test('abcd')) // matches
![/a/, /b/, /c/, /d/].find(r => !r.test('abcd')) // not matches
Add "precommit"
script into package.json
npx mrm lint-staged
— https://paulund.co.uk/local-storage-vs-session-storage-vs-cookie-storage
https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker
They are all same sequence: 13pt, 14pt, 15pt, 16pt, 18pt, 21pt, 24pt Assume that 1rem = 10px or 10pt
:root {
font-size: 100%;
}
h1 {
font-size: 2.1rem;
}
p {
font-size: 1.3rem;
}
<meta name="robots" content="noindex, nofollow, noml">
X-Robots-Tag: noindex, nofollow, noml