Regarding rem <-> px conversions, I follow this intuition: _multiply by 4 gives you px value, dividing by 4 gives you rem value._
`h-8` utility is height of 8 * 4 = 32px or 8 / 4 = 2 rem.
Since design systems are supposed to be consistent, 4px is typically considered 1 unit of distance.
However, there are times when I might encounter values in Figma (or get inputs from designer) that won't allow me to use this easily.
Say, designer wants a max-width of 252px on an element. I usually use Alfred app on my work MBP to divide it quickly by 16 (since 1 rem is 16px under normal font-size settings), but you can use any calculator, even the one in Google search or DDG search.
It turns out to be a fraction, and in this case, it's 15.75 rem.
I use utility like `max-w-[16rem]`, closest consistent dimension that's a multiple of 1rem, and ship a pull request preview to the designer, asking for design feedback.
Chances are, designer agrees to stick to 16rem, and we ship it as is. If this width of 16rem, or closer values within the 250px vicinity, are used in other places in the design system components or our app; I'd typically add that to the Tailwind config as well.
Most of the time question of rem <-> px conversion comes into picture because we look at design dimensions in Figma / Sketch / Indesign etc. tools, and try to implement the same in our UI code.
But this would only slow down a developer, switching back-and-forth between design and implementation.
What I find more productive while prototyping a UI (or a smaller component), is to just "eye it", instead of getting actual pixel-values right at the first go.
From just eye-ing it, I can make a guess if it should be h-3 or h-4 (you can also guess the right value using a binary search style heuristic), and if my implementation looks bigger (or smaller) than the design, I'd adjust accordingly.
Only after I've implemented a basic prototype of the UI component, I'd cross-check with the design tool, and edit some utilities if necessary to get as close to the design as possible.
I've had some experience migrating large UI projects at work to use a design system based on Tailwind. Haven't faced any issue with Tailwind at all, even while integrating in existing projects.
Tailwind is a different way of writing CSS, with some guard-rails coming in from the design system consistency. Tailwind also provides sane defaults (rem over px, for instance).
If someone's bad at writing or thinking in CSS, chances are, they'd be bad at Tailwind too.
I've found Tailwind helps me focus on writing the CSS that matters. But just having Tailwind CSS in a project won't automagically fill one's gap in CSS knowledge.
This isn't bootstrap, where one can use some col-* utilities and magically get a grid layout that just works across browsers.
Tailwind is a bit lower level, and to achieve similar responsive layout, you still have to know how to do that with CSS grid, what the breakpoints are etc.
Where Tailwind aids here, is by providing utility classes that help with original CSS grid intuition. For instance, `grid-cols-2 sm:grid-cols-4 md:grid-cols-6` would be hard to achieve by hand, writing vanilla CSS or styled-components.
> A bigger project with multiple pages having full on Tailwind css classes peppered everywhere looks to be a nightmare.
Ideally, you would be using a framework to help organize code better. Most likely React or Vue or something similar.
In which case, you'd already have components.
There are more than one way to achieve same look and feel, with CSS. Similarly, one can apply some discipline with using Tailwind's utility classes, when building anything.
Two heuristics that have worked for me, are:
- Never use margin if you can, use flex-box and grid with gaps instead. Placing a children node is parent's responsibility.
- Write symmetric CSS. Prefer px over pl or pr, mx over ml or mr etc.
Using margins make it hard to extract some React markup as a reusable component. Using symmetric CSS gives you automatic RTL compliance without using any of the CSS logical properties.
Sure, there'd be times when a UI design cannot be implemented without breaking some of these. But in most cases I've encountered at work, building consistent UIs, have been easy for me and my team following these.
Happy to go into details with code examples, if anyone's interested.
”Never use margin if you can, use flex-box and grid with gaps instead. Placing a children node is parent's responsibility.”
Good idea, but importantly only applies to flex and grid layout, not paragraph-like blocks of content.
It is not a good practice to use flexbox for layout, especially if there are nested flexboxes. It takes a lot of time to recalculate such a layout, which can be seen when resizing a desktop browser, or when advertisements load on the page and the layout shifts.
”Write symmetric CSS. Prefer px over pl or pr, mx over ml or mr etc.”
Usually but not always. For example, text boxes can look more visually symmetric with less padding on the ragged side, while interaction-heavy mobile layouts may want to have a larger padding on the right to give the user something to safely scroll.
The symmetric bit is a good idea. I recently joined a team that maintains a multilingual LTR/RTL site so I'm learning some of these lessons the hard way.
Padding > Margin can also be a good idea, even if working vertically. Padding cannot collapse which is usually what you want. Obv, ymmv.
At work, we've built a component library styling readily available headless components from Radix UI, Headless UI, Reach UI etc. with a customized Tailwind CSS preset.
We had to use `rtl:` directive only in one component, where we were animating translation property, of a switch toggle. `translation-x-` is RTL specific, so we've to apply negative translation if `dir="rtl"` has been set.
Otherwise, this symmetric-utilities-only approach worked really well across dropdowns, modals, tooltips, buttons, inputs etc., even when we integrated these components in different existing products across multiple teams.
I hope one day Tailwind CSS team release an update with underlying CSS for px-, mx-* being replaced with CSS logical operators for corresponding properties. Not sure where the browser support for the same is currently.
I found that one can make Tailwind CSS utility classes appear vertically, if one's been using clsx library[1] (or something similar). clsx accepts an array, and at that point, prettier formatting kicks in.
You could have a React `<Button>` component's styling go like this, with clsx and Tailwind:
```
<Button
type="button"
className={clsx([
"inline-flex items-center", // how its children nodes should be laid out
"px-3 py-2",
"bg-gradient-to-r from-blue-500 to-indigo-500", // background color stuff
"rounded-md", // border radius
"text-white", // text color of children nodes
"outline-none hover:ring-4 focus:ring-4 ring-blue-500/40", // hover focus behavior
"disabled:hover:ring-0 disabled:cursor-not-allowed" // disabled state
"disabled:bg-gradient-to-r disabled:from-blue-400 disabled:to-indigo-400"
])}
{...props}
>
Click Me
</Button>
```
There are other benefits to using a library like clsx. Since clsx accepts array of strings and returns a joined string based on conditional, output of one clsx call can be consumed by another clsx call.
I'm not sure why you believe this would be a difficult task to achieve.
You've already mentioned in the other comment, that drift is your concern, and that can be fixed easily. Though it has nothing to do with hooks. One has to track the time when the clock starts, and query current time on every tick.
As for creating a setInterval() and tearing it down after every render, you can simply pass an empty deps list, instead of declaraing counter variable as a dep in the array. Or, if you want to keep ESLint happy, declare counter as a dep, but use `setTimeout()` instead of `setInterval`
But this code wouldn't be that different if you wrote it in class fashion, except you'd be making a few of calls to this. Most of this would go in componentDidMount and the cleanup would go in componentWillUnMount
Where hooks really shine, is if you want to add / extend this functionality.
Say, you now want the counter to pause when you're not looking at that tab, and resume once the browser tab is in focus. Imagine if you had a pageVisibility API hook, and it returns true and false accordingly, based whether or not the tab is visible at any point of time or not.
In a real-world scenario, it'd not be a basic counter, but maybe an API polling for real time data, and user don't want the page to keep on polling when not in focus.
In that case, you'd have two changes: one call to the useVisible hook, and one more to pass the boolean output of this hook into your Effect hook.
Now, let's go one step further, and add local-storage / indexed DB for storing these values, on page close. If you close the page, and re-open, it should resume from where it was before closing, and then count up from there - not zero.
All we need now, is another hook, that abstracts away that storage interaction, storing on window.unload and componentWillUnMount, and retrieving value from storage when component mounts for the first time.
After this point, it'd be illuminating to look back and try to combine these three functionalities, using class components with HOC or Render Props pattern; and think about the effort it'd take to decouple and reuse the count-up logic, from the page visibility logic, from the storage logic.
In India, Spotify Premium is 119 INR / month, while Apple Music is 120 INR / month. Spotify also have few other options, like annual membership, and student plans.
While recommendation is off the charts, the collection simply isn't there. Mostly due to licensing issues, I assume.
For instance, really loved the tracks from Suits, and got my own playlist on YouTube too, consisting off some nice tracks compiled from tunefinder.
But the Spotify track list is only a subset, and not all those tracks are available.
Am on iOS, so no Google Pay Music on phone, and for me Apple Music is no worse than Spotify, except when it comes to search.
In my experience Apple Music is really good. I have found almost all songs I have searched for. Everything including very old regional songs to international indie artists and Japanese anime openings.
PS. Suits soundtrack was one of the very first things I searched for and found many playlists with most tracks on it. And tunefind actually provides direct links to Apple Music so that you can immediately add it to your library.
Have been developing with React for last 3 years, and recently started building with Vue JS.
React's core philosophy is JS everywhere - there's no template, no HTML, no CSS; only JS. As much as possible, write JS, and if you can, pure JS.
It has its benefits - you can have code formatter to format your JSX, unit test any part of your code, or write integration tests with mount, or write snapshot tests. Extremely easy and natural to compose various components - because it's a function calling another function.
Vue is magic, and its own DSL rules will get in your way. For instance, inside the Vue templates you cannot use `this`. However, inside your methods and computed, you have to.
Coming from Angular 1, Vue JS would look feel like a breeze.
Never could make ESLint work on my Vue files, tried all plugins. Some parts of the code it lints, and some parts of the code it doesn't.
Inside your template, Vue.config can be undefined; so you've to assign it to something in mounted(), and then get it to work.
Vue artisans tell me Vue supports "this" or "that". I don't want something that supports A or B - I want something where A and B are inherently supported from the ground up.
It's not all bad. VueX is pretty cool, kinda like Redux without the drama. And I cannot stress this enough - it's insanely easy to go through a Vue codebase and pick up the business logic of your app.
It still takes me some time to get used to a new React codebase.
Overall, I felt Vue is really good to build MVP and get your product off the ground, but it starts to show why you need React's discipline in your codebase with growing requests from users to add new features and support more platforms.
Then again, I'm new to Vue JS; so ask me again in a year. Am keeping an open mind.
> Vue is magic, and its own DSL rules will get in your way. For instance, inside the Vue templates you cannot use `this`. However, inside your methods and computed, you have to.
Except everyone seems to complain that "this" exists at all, but then it's confusing that "this" is implicit inside an objects own template?
The DSL is awesome, and what makes it even more awesome is that it's optional. Your options are HTML, Jade/Pug, JSX, and a literal vanilla function. After the compile process, the template ends up as a render function.
> Never could make ESLint work on my Vue files, tried all plugins. Some parts of the code it lints, and some parts of the code it doesn't.
I can't say for sure this was true a year or more ago (especially in that short time you couldn't tell which libraries supported Vue 1 or 2 or both), but today and for as long as I've remembered eslint has been working in my Vue component files and inside sublime linter. My biggest complaint is that I want reasonML.
However, if you add your own CI runners, you'd have to clean them up periodically. This was the biggest issue for us, because even after cleaning them up from all docker images once a week, builds would get stuck.
We run buildkite-agents in its own kubernetes cluster, and the nodes are pre-emptible on Google Cloud so 30% of the price and it dies everyday, so it gets cleanup automatically
Gulp is a tool that lets you decide what the build process should look like.
Webpack is a tool where you define entry points, split points etc., and what you finally need. Based on that webpack decides how to go about the build.
Most of what Gulp does, can be replaced with NPM scripts.
it's the streaming/caching side of gulp that I find most useful to be honest. When I have 3-4 build outputs being generated and I can offload intermediate objects into a cache file and back it can lead to really fast builds. In replacing grunt with gulp and setting up gulp correctly I've reduced builds from 10-15 seconds to nearly instant before, and I think the main failing of webpack is how slow a non-watch build can run, or how large its output size can be. I think entrypoints and code splitting could be achieved with a gulp-like system by picking files to be packaged into different builds.
It's also very easy to find build bottlenecks with gulp which is very handy if you have a large project with a slow build. It allows you to scale out efficiently.
Webpack hot reload server solves this problem and provides nearly instant builds.
Yes, production (“non-watch”) builds can take a while. But who cares? You shouldn’t be running a production build after every code change. That’s why the hot reload server is so useful; it only recompiles the code you changed.
`h-8` utility is height of 8 * 4 = 32px or 8 / 4 = 2 rem.
Since design systems are supposed to be consistent, 4px is typically considered 1 unit of distance.
However, there are times when I might encounter values in Figma (or get inputs from designer) that won't allow me to use this easily.
Say, designer wants a max-width of 252px on an element. I usually use Alfred app on my work MBP to divide it quickly by 16 (since 1 rem is 16px under normal font-size settings), but you can use any calculator, even the one in Google search or DDG search.
It turns out to be a fraction, and in this case, it's 15.75 rem.
I use utility like `max-w-[16rem]`, closest consistent dimension that's a multiple of 1rem, and ship a pull request preview to the designer, asking for design feedback.
Chances are, designer agrees to stick to 16rem, and we ship it as is. If this width of 16rem, or closer values within the 250px vicinity, are used in other places in the design system components or our app; I'd typically add that to the Tailwind config as well.
Most of the time question of rem <-> px conversion comes into picture because we look at design dimensions in Figma / Sketch / Indesign etc. tools, and try to implement the same in our UI code.
But this would only slow down a developer, switching back-and-forth between design and implementation.
What I find more productive while prototyping a UI (or a smaller component), is to just "eye it", instead of getting actual pixel-values right at the first go.
From just eye-ing it, I can make a guess if it should be h-3 or h-4 (you can also guess the right value using a binary search style heuristic), and if my implementation looks bigger (or smaller) than the design, I'd adjust accordingly.
Only after I've implemented a basic prototype of the UI component, I'd cross-check with the design tool, and edit some utilities if necessary to get as close to the design as possible.