Visualize Easing Animation Curves
easings.net has a handy table for visualizing easing functions for animation curves.
easings.net has a handy table for visualizing easing functions for animation curves.
In Tailwind you can use certain classes to wrap text within an element.
You could use something like text-wrap
or whitespace-pre-wrap
, or any of the other classes.
However, if a single word is too long it will continue on past the element it is contained in.
Kind of like this:
<div class="text-wrap">
<!-- really long text -->
</div>
HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword
Well, just add the Tailwind class break-words
and it will break up a word when it reaches the end of the element, and you'll get something more like this:
<div class="text-wrap break-words">
<!-- really long text -->
</div>
HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword
The HTTP 418 I'm a teapot client error response code indicates that the server refuses to brew coffee because it is, permanently, a teapot.
'Nuff said.
Check out the docs to learn more.
Thanks goes to Tony for making me aware of this.
You can open a new tab on form submit by changing the target
attribute of the form element:
<form target="_blank">
<!-- ... -->
</form>
While this is useful, it doesn't handle the scenario where you have multiple submit buttons (different actions) that need to behave differently.
For that, there's the formtarget
attribute on your submit button/input. Note that by setting this attribute, you will override the form target
attribute if set.
In the example below, the "Save" button will submit the form in the current window, while the Preview window will submit the form in a new tab
<form action="/liquid-templates/1">
<!-- ... -->
<button type="submit">Save</button>
<button type="submit" formaction="/liquid-templates/1/preview" formtarget="_blank">Preview</button>
</form>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#target https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#formtarget
You can change the underline offset spacing with the Tailwind class underline-offset-{width}
The :host
declaration in CSS is a functional pseudo-class used in Web Components, specifically within Shadow DOM. When you create a custom element with Shadow DOM, the :host
pseudo-class allows you to define styles that will apply to the host element of the shadow tree. This means you can style the custom element rather than just its content. For instance, if you create a custom <my-element>
tag and attach a shadow DOM to it, using :host
in your CSS (inside the shadow DOM) lets you set properties like background color, margin, or padding directly on <my-element>
. This is particularly useful for encapsulating styles in web components, as it allows the component to have its own isolated styling that doesn't bleed into the rest of the page or get affected by external styles.
There are several ways to get your text to wrap with css. However it always seems that there ends up being an orphan piece of text on the wrap. The newly introduced pretty
option for text-wrap
aims to fix this.
Image sourced fromΒ Why you should remove orphans from your body text.
Like i mentioned earlier it is a new feature and is not fully supported in all browsers yet but definitely a welcome addition.
Using Tailwind you can apply custom styling to an element based on it's data attribute.
For example, given these elements:
<div data-state="checked" class="data-[state=checked]:bg-black bg:white">
<!-- Html that could change the data-state goes here -->
</div>
<div data-state="unchecked" class="data-[state=checked]:bg-black bg:white">
<!-- Html that could change the data-state goes here -->
</div>
Of these two elements, the first one would be given a black background, while the second one would have a white background, unless it's data-state changes to checked.
One of the main reasons I used Sass was just to get nesting of my styles. Apparently it was finally rolled into CSS.
So what you had before:
.nesting {
color: hotpink;
}
.nesting > .is {
color: rebeccapurple;
}
.nesting > .is > .awesome {
color: deeppink;
}
Now turns in to:
.nesting {
color: hotpink;
> .is {
color: rebeccapurple;
> .awesome {
color: deeppink;
}
}
}
Find out more at the Chrome developer page for CSS Nesting
https://realfavicongenerator.net/ can audit your website's favicon's to show which devices and browsers will display your favicon properly.
The site also helps with favicon generation and target resolutions.
Tailwind supports styling for browsers using Dark Mode
. This is done by simply prepending dark:
to your tailwind classes.
<div class="dark:bg-slate-700 dark:text-white">
Sample text
</div>
By default this uses the prefers-color-scheme
, which is determined by the browser.
To read more about this, or other ways to use dark mode with Tailwind, you can check out the official tailwind documentation for yourself.
With Tailwind's accent-{color}
class, you can customize your form's colors. On your input, simply add the class along with the color of your choice like this:
<input type="checkbox" class="accent-red-300" checked>
And the result looks like this! (its an image btw, I'll save you a click)
This works for the accent colors of radio groups as well.
Turns out that even with modern email we cannot rely on SVG file support.
The Google image proxy that every image gets served by when mail is processed through Gmail will not serve your SVG content.
This is a long standing issue and apparently will not be fixed.
You can possibly use inline SVG or a failover via the image tags src
& srcset
attributes, however, just converting to PNG/JPG will end up being the least problematic.
You can set custom values in tailwind, without customizing your theme like this:
<div class="w-[50rem]">...</div>
This bracket syntax works with basically anything in tailwind. For example, here's font size.
<p class="text-[14px]">...</p>
This is super helpful at times when you don't want to bother with tailwind's size classes.
You can use tel: and mailto: to make phone and email links in markdown like this:
[Call Me!](tel:1111111)
This is equivalent to:
<a href="tel:1111111">Call Me!</a>
Similarly, for email links you can use:
[example@example.com](mailto:example@example.com)
HTML equivalent:
<a href="mailto:example@example.com">example@example.com</a>
Today I Learned there is a repeat
function in CSS, where
grid-template-columns: repeat(3, 1fr)
is equivalent to
grid-template-columns: 1fr 1fr 1fr
Have you created an amazing print version of your html page and when you go to print it out, it's not looking quite the same?
Hey those background colors are all missing!
Turns out that your user-agent (browser) is given control on how your elements should appear in different scenarios, like printing.
This is why when you print out a page with a background image, said image is generally not printed and you get a clean print.
Here the stamp style looks super elegant with our cornflowerblue
background but when printing that we lose the look of the stamp due to the background being missing.
.stamp {
background-color: cornflowerblue;
border-radius: 5px;
padding: 10px;
}
There is a way to control this though. The print-color-adjust
css directive can be set so that your styles will do your printable bidding.
By default print-color-adjust
is set to economy
. I like to think of this as if we're saving money in unused ink.
With a small change to:
.stamp {
background-color: cornflowerblue;
border-radius: 5px;
padding: 10px;
print-color-adjust: exact;
}
We now get our stamp style that looks great in our browser to look great on a printed page as well.
If you need to add !important
to one of your Tailwind classes, you simply need to add !
before the class name.
Here is a crude example:
<div class="bg-red-500 bg-blue-500">
<!-- Insert content here -->
</div>
<div class="!bg-red-500 bg-blue-500">
<!-- Insert content here -->
</div>
When using this with responsive breakpoints, place it after the variant modifier.
<div class="md:!bg-red-500">
<!-- Insert conent here -->
</div>
<div class="!md:bg-red-500">
<!-- Insert content here -->
</div>
We like to use SVG sprites
However, if you utilize a cdn or serve assets from an external source... you may run into some issues. Hopefully you find this and it saves you time that we lost figuring this out
According to MDN:
For security reasons, browsers may apply the same-origin policy on use elements and may refuse to load a cross-origin URL in the href attribute. There is currently no defined way to set a cross-origin policy for use elements.
When using flex in CSS, gap
is a shorthand combination of the row-gap
and column-gap
properties. You can use this to set the amount of space between flex items.
.gap-example-container {
display: flex;
gap: 2em;
}
If you ever find yourself with conflicting rules on an element, and want one to take precedence even over rules with higher specificity. you can add the !important
property, to override all other rules.
Here is an example:
#id {
background-color: blue;
}
.class {
background-color: gray;
}
p {
background-color: red !important;
}
<p>This is some text in a paragraph.</p>
<p class="class">This is some text in a paragraph.</p>
<p id="id">This is some text in a paragraph.</p>
In this case, all of these <p>
tags will have a red background.
There is a CSS property filter
which allows you to manipulate properties of an element such as their blur, brightness, contrast, grayscale, opacity, and more. This is most often applied to images, but does work on any element.
.single-filter {
filter: opacity(50%);
}
.multiple-filters {
filter: blur(5px) grayscale(100%);
}
Here comes our friendly neighborhood Pikachu to help show us what this looks like:
Here is a good reference for what filter
can do.
You can style an element with css if its id attribute matches the window location's hash using the :target
pseudo-class:
<style>
#content {
display: none;
}
#content:target {
display: block
}
</style>
<a href="#content">See hidden content</a>
<table id="content">
<legend>Keep is secret!
<tr>
<td>Keep it safe!
</table>
https://developer.mozilla.org/en-US/docs/Web/CSS/:target
Recently, I found myself with a form that needed to be able to submit to multiple urls. You can definitely use some javascript to get around this but that seemed like overkill for my situation. That's when I learned about the HTML formaction
attribute.
You can use this attribute on a submit tag and it will override the action specified by the form
. Here's an example with a Ruby on Rails form, but you just as easily do something similar with plain HTML -
<% form_with url: false do |f| %>
<% users.each do |user| %>
<%= check_box_tag "user_ids[]", user.id, false %>
<% end %>
<%= f.submit "Assign to Users", formaction: "/users/assign" %>
<%= f.submit "Print for Users", formaction: "/users/print" %>
<% end %>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
It looks like Tailwind 3.1 will have support to arbitraty variants which will allow you to style children elements from the parent class.
Example of the famous zebra pattern:
<ul class="[&>*:nth-child(even)]:bg-gray-300">
<li>Z</li>
<li>E</li>
<li>B</li>
<li>R</li>
<li>A</li>
</ul>
The tabindex
attribute on HTML elements behaves differently than one might first expect.
The default tabindex
for an element is 0
, all elements with this index will be tabbed to in the order they appear in the document.
Giving an element a positive tabindex
will prioritize it over all elements with a 0
index, in the order they appear.
Consider the following code
<ul>
{
[0,1,2].map((n) => (
<li><button tabindex={n}>{n}</button></li>
)
}
</ul>
The order that the buttons will be focused when tabbing is 1
, then 2
, and finally 0
.
HTML5 has a <datalist>
element which you can you use to create suggestions for inputs.
Just specify the list
attribute on your input, whose value should correspond to the id
of the datalist
, and then populate your datalist
with options:
<input list="programming-languages" id="programming-language-choice" name="programming-language-choice" />
<datalist id="programming-languages">
<option value="Ruby">
<option value="Elixir">
<option value="Java">
</datalist>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
With Tailwind 2.2 now you can easily use before
and after
pseudo selectors.
Here's an example:
<p class="flex flex-row items-center before:mr-2 before:bg-gray-400 before:h-2 before:w-2">
Hello Tailwind 2.2
</p>
There are other great new features added to version 2.2, check them out here.
If you want a list of things to have an interesting bullet, besides the standards that you get with list-style-type, you can use list-style-image to get something fancy!
Chrome dev tools has now a flexbox helper button that drops down a bunch of most used flexbox features so we can use them to play around. To see that you can update your chrome, then inspect a DOM element, add a display: flex
and the button will appear. Have fun!
Some codebases use data attributes for automated testing, and today I learned how to access and manipulate these attributes from a DevTools console.
document.querySelector(`[data-test-attribute="submit-button"]`).click()
This technique lets me visually verify that the attribute is in the right place and behaves as test software expects it should, without reading the HTML at all.
This is a companion to my previous post about inline HTML styles. If you want to put your images inline in your HTML, GNU coreutils provides the base64
program.
Here's me running it in Vim command mode, sending the output right to my current line:
:.! base64 -w 0 public/images/bg.gif
The -w 0
disables line wrapping, which I don't want for inline images. Prefix this string with "data:image/<MIME TYPE>;base64,"
and you're good to go.
I like my exceptional pages (404, 500, 503) to rely as little as possible on the webserver to render in the browser. A nice tool to support this is CSS Used for Chrome.
CSS Used adds a panel to DevTools that reports which CSS classes from external stylesheets are being used on your page. You can then paste these styles inside a style
tag and remove stylesheet references in your HTML. I iterate on this by opening the HTML file in my browser outside of my project repo; when all the styles are loading, I've removed the stylesheet dependency.
You can effectively "crop" images in CSS by setting the property object-fit: fill | cover | contain | none | scale-down;
Read more about it here https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
#654321
I've been hacking on TIL to optimize our site for Safari Reader mode. A lot of this is black box, because Apple doesn't have easy-to-find documentation about how the feature works.
One thing that seems to matter is a class called byline
for your author information, and an HTML tag time
for the publication date. Here's an example, borrowed from this site:
<p class="byline">
<%= name %>
<time datetime="<%= inserted_at %>">
<%= inserted_at %>
</time>
</p>
It gives us relevant reader information, shown here in Safari:
Here's the PR:
https://github.com/hashrocket/tilex/pull/650
When writing HTML, make sure that your meta charset
tag is in the first 1024 bytes on the page.
Per MDN:
The
<meta>
element declaring the encoding must be inside the<head>
element and within the first 1024 bytes of the HTML as some browsers only look at those bytes before choosing an encoding.
What does this mean practically? Keep this tag near the top of your document, and use a website validator like https://validator.w3.org to check your tag placement.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
Have a script
tag in your HTML annotated with <script type="text/javascript">
? Per the HTML5 specification, the MIME type of a script
tag, when omitted, is text/javascript
. We are encouraged to omit it.
Delete that code and go green π.
Per MDN:
Omitted or a JavaScript MIME type: This indicates the script is JavaScript. The HTML5 specification urges authors to omit the attribute rather than provide a redundant MIME type. In earlier browsers, this identified the scripting language of the embedded or imported (via the src attribute) code. JavaScript MIME types are listed in the specification.
Source:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
The TextInput
component in react-native has a property of placeholderTextColor
that allows you to configure the placeholder text color! However, react-native-web
does not have this property and it must be done in css. So if you were using react-native-web
you would need to include .css
file:
// screen.tsx
import "./styles.css";
import { TextInput } from "react-native";
const Screen = () => (
<TextInput
testID="change-placeholder-color"
placeholder="enter some text"
defaultValue=""
/>
);
/*************
*
* styles.css
*
**************/
[data-testid="change-placeholder-color"]::-webkit-input-placeholder {
color: skyblue;
}
[data-testid="change-placeholder-color"]::-moz-placeholder {
color: skyblue;
}
[data-testid="change-placeholder-color"]::-ms-placeholder {
color: skyblue;
}
[data-testid="change-placeholder-color"]::placeholder {
color: skyblue;
}
Services that render fenced code blocks tend to remove whitespace. They'll display these two code blocks the same way, trimming the blank lines from the second example.
let something;
let something;
GitHub does this, as does Deckset. Deckset also adjusts your code's font size based on how many lines are in the block, which means these two code blocks would have different font sizes on their slides. Sometimes I don't want that to happen, like when building a series of slides that fill in different pieces of an example and should look consistent.
I cheat this feature putting a non-breaking space on the last line. On Mac, I can do this with OPTION + SPACE
. I can see the character in Vim ('+
'), but it's invisible on the slide, and it prevents Deckset from collapsing the line it's on, forcing the code block to the length I choose.
Markdown parsers have a neat feature: a list of any numbers tends to be turned into an ordered lists.
I write:
99. First thing (?)
1. Second thing (??)
50. Third thing (??)
1. Fourth thing (????)
And TIL's markdown parser (Earmark) produces this as HTML:
Pretty cool! Sometimes I want to do my own thing, though. This Stack Overflow question elicits a bunch of techniques; the kind I learned today and used with success is:
99\. First thing (?)
1\. Second thing (??)
50\. Third thing (??)
1\. Fourth thing (????)
Escape the pattern; break the system! This perserved my unordered numbering. Now, I may have other problems, like losing automatic ol
and li
tags, but the hack works.
The user-select
css property governs if text is selectable for a given element.
user-select: none
means that it is not selectable.
What's interesting about this property is that while each browser supports it, they each require their own prefix, except Chrome, which does not need a prefix.
In create react app, what starts out as:
user-select: none;
Gets expanded to:
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
But the default browserList configuration for development in your package.json
file is:
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
And so in development, it gets expanded to:
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
Sorry Micrsoft.
How does create react app know which prefixes to render? The caniuse-lite
npm package has up-to-date support data for each property and user-select:none
is defined here.
That data is compressed. Here's how to uncompress it using the node cli to see what it represents:
const compressedData = require('caniuse-lite/data/features/user-select-none');
const caniuse = require('caniuse-lite');
const unpackFunction = caniuse.feature;
unpackFunction(compressedData);
This is accomplished in create react app by the npm package autoprefixer;
Today I learned about the 'diff' syntax, supported by many syntax highlighting libraries including those used by Github and Today I Learned.
Add diff
to your fenced code block, and this:
def example do
- :ok
+ {:ok, :more_stuff}
end
Becomes this:
def example do
- :ok
+ {:ok, :more_stuff}
end
A nice use case is a README or pull request description; show instead of tell the changes you made, or someone should make.
The :root
CSS pseudo-selector and html
will target the same element --
<html>
, but :root
has higher specificity. That means the property rules
declared under :root
will take precedence over those under html
.
:root {
background: red;
}
html {
background: blue;
}
In the case of the above code, the <html>
element's background color will
be red
.
HTML has a tag named <ruby>
that allows you to add extra characters to the main text. This is useful for annotating the pronunciation of Kanji.
According to https://www.w3schools.com/tags/tag_ruby.asp:
A ruby annotation is a small extra text, attached to the main text to indicate the pronunciation or meaning of the corresponding characters.
<ruby>θͺ<rt>γ</rt>γ</ruby>
will look like this:
Why is .ad-inner
set to display: none !important
? It's because I'm using uBlock Origin, a fantastic ad blocker. It makes the internet tolerable. But it completely breaks the site I'm working on because a previous dev on the project chose ad-inner
as a class name.
It turns out, there are a lot of class names that you shouldn't use. Class names, ids, even certain dimensions applied as inline styles. uBlock Origin sources its rules from about 8 different lists, and the list that contained a rule for .ad-inner
is EasyList. EasyList is hosted on github and the particular file with selector rules is easylist_general_hide.txt
Here are all the class names in the list that begin with .ad-i
##.ad-icon
##.ad-identifier
##.ad-iframe
##.ad-imagehold
##.ad-img
##.ad-img300X250
##.ad-in-300x250
##.ad-in-content-300
##.ad-in-post
##.ad-in-results
##.ad-incontent-ad-plus-billboard-top
##.ad-incontent-ad-plus-bottom
##.ad-incontent-ad-plus-middle
##.ad-incontent-ad-plus-middle2
##.ad-incontent-ad-plus-middle3
##.ad-incontent-ad-plus-top
##.ad-incontent-wrap
##.ad-index
##.ad-index-main
##.ad-indicator-horiz
##.ad-inline
##.ad-inline-article
##.ad-inner
##.ad-inner-container
##.ad-innr
##.ad-inpage-video-top
##.ad-insert
##.ad-inserter
##.ad-inserter-widget
##.ad-integrated-display
##.ad-internal
##.ad-interruptor
##.ad-interstitial
##.ad-intromercial
##.ad-island
##.ad-item
##.ad-item-related
A good rule of thumb is to not start a class name with .ad
. This survey says that 30% of users are using ad blockers.
There is an HTML tag that tells browser engines to render text as superscript -- like when you need an exponent.
<p>Render this text as <sup>superscript</sup>!</p>
Here is what the above would look like:
Check out this codepen example to play around with it.
I'm trying to put a before image to the left of some text. But I want the text to NOT wrap below the image. The image is only 40px tall but the text can be any height.
<div class="text">
Many many words
</div>
.text {
width: 200px;
&:before {
background-image: url('carrot.png');
}
}
When I do this the words wrap under the carrot. To fix this I can use the absolute top 0 bottom 0 technique to give the before pseudo element full height.
.text {
width: 200px;
position: relative;
padding-left: 32px;
&:before {
background-image: url('carrot.png');
position: absolute;
top: 0;
bottom: 0;
left: 0;
}
}
Now none of the text wraps under the carrot.
You can tie a submit button to a form that the button doesn't live inside
of. The trick is to give the form an id
and then reference that id
with
the button's form
property.
<div>
<form id="my-form">
<label for="name">Name:</label>
<input type="text" name="name"></input>
</form>
<!-- ... -->
<button type="submit" form="my-form">Submit</button>
</div>
With this setup, clicking the Submit button will cause the form to be submitted.
See the MDN Button docs for more details.
Today I learned about a CSS property called user-select
. You might use it like this, to prevent a user from selecting text:
p {
user-select: none;
}
I discovered this on an event booking website: the event description links were not anchor tags, and the content on the page was not selectable.
If you're going to disable default behavior on a website, you need to have a good reason. My assumption (which could be wrong) is that the site creators don't want me to select text on the page and start searching around for a better deal. I don't think that's a good enough reason, because there are plenty of cases where a user might copy text on a page that don't hurt (or actually support) the event organizer's business.