Buy Me a Coffee at ko-fi.com
Strategy

Migrating from Parcel to Snowpack – build tool comparison – …


Here’s the YouTube version of Migrating from Parcel to Snowpack if you would rather?

A couple of years ago I wrote about moving from Gulp to Parcel. Parcel has been a good tool for me. In the day job I’m typically building prototypes of new features. As what I build is almost never destined for a production environment, output of the build tool is less important to me than the ease of getting it running and it getting out of the way while I iterate on whatever I’m building.

So, suffice it to say, WebPack was never an option. 😉 But this is something Parcel excels at, living up to its promise of being almost configuration free.

Parcel has been moving to version 2 for some time. Now, I don’t know anyone in the Parcel team but from an outsiders point of view the transition from v1 to v2 has been a little chaotic. I’ve never been quite sure when (if!) v2 was ready or when the time to transition was right.

In the meantime, a newer tool called Snowpack has been piquing my interest, and to a lesser extent, Vite.

The USP of Snowpack is it does less. Rather than compile and transpile everything on every save, it only compiles the files that have changed. And it some cases, if your writing modern JavaScript, it won’t even transpile it, it will just send it ‘as is’, directly to the browser without writing anything to the file system at all.

We’ll look at what that means in practice in a moment but conceptually, this approach appeals to me a lot. I basically want my CSS (or PostCSS/Sass) processed, my TypeScript compiled and a fast reloading server spun up with as little configuration as possible. And I want my feedback loop as fast as possible as I iterate.

So I decided to try Snowpack. It’s version 3.2.2 as I write this.

Migrating from Parcel to Snowpack wasn’t quite as straightforward as I thought or hoped it might be. Whether that is due to naivety or ineptitude on my part, or a lack of clear documentation, I cannot say for sure. Probably all three in some measure. But this serves as a few notes that I hope saves others some time if you’re following a similar path.

I’ll start with the more important, conceptual differences between Snowpack and Parcel and move on to things like running Snowpack, getting Sass compiling quickly, and getting module import paths for scripts working.

There is no build destination

It took an embarrassing amount of time for me to get my head around how Snowpack fundamentally works.

In virtually every build tool I have used or pieced together myself (earliest post on this subject is from back in 2013!) over the last 9 years or so, you have a ‘src’ folder of some sort, where your ‘authoring’ SCSS/TS files live, and a ‘dist’ or ‘build’ folder where the compiled JS/CSS/Whatever files end up. The built in server uses the dist/build folder as the root it serves up in the browser.

And that’s essentially what Parcel does.

How Parcel works

What I love about Parcel is you don’t have to tell it where all your source files are. It is smart enough to look at what is referenced in your index.html, your entry point in build tool parlance, and pull things in from there. For example, your simplified index.html might look like this :

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0, viewport-fit=cover"
        />
        <link rel="manifest" href="manifest.webmanifest" />
        <title>Parcel</title>
        <link rel="shortcut icon" href="./faviconAlt.ico" />
        <link rel="stylesheet" type="text/css" href="styles.scss" />
    </head>

    <body>
        <script src="app.ts"></script>
    </body>
</html>

To be clear here, notice how with Parcel, the index.html is referencing the authoring languages (Sass and TypeScript) for the styles (styles.scss) and scripts (app.ts)? That’s how Parcel is able to deduce all the things it needs to pull in and compile.

It reads those initial files and then reaches out its build tool tentacles, like some ‘file system Kraken’, and drags in all needed dependencies. It then does its magic, transforming these dependencies, and spits that all out to a ‘dist’ folder with all files at pretty much the same root level, regardless of how your files and folders are organised when authoring.

So, given a folder with this kind of (simplified) hierarchy:

index.html
styles.css
app.ts
interface/
  component-one/
    component-one.scss
    component-one.ts
  component-two/
    component-two.scss
    component-two.ts
mockserver/
  server-responses.ts
  mock-data.json
global-images/
dist/

Parcel will flatten the files, and cache bust the names, as needed, into that dist/ folder. For example, you might end up with something like this, with components compiled down into that single app.7a013482.js file, and all styles compiled into the styles.d3ll04e9.css:

index.html
styles.d3ll04e9.css
app.7a013482.js

So that’s the essence of Parcel.

How Snowpack works

Things are a little different in Snowpack land. In Snowpack land, your index.html file needs to reference the transformed version of the files – even though they don’t exist on your file system.

Wait, what?

Let me say that again as it’s jolly important. You link to files that don’t exist. Here is the index file as it would exist in Snowpack land:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0, viewport-fit=cover"
        />
        <link rel="manifest" href="manifest.webmanifest" />
        <title>Snowpack</title>
        <link rel="shortcut icon" href="./faviconAlt.ico" />
        <link rel="stylesheet" type="text/css" href="/styles.css" />
    </head>

    <body>
        <script src="/app.js"></script>
    </body>
</html>

See how we are linking to files in the root with the forward slash? Yes, that /app.js and /styles.css doesn’t actually exist on your file system. I found that utterly bonkers. Not in a bad way – in a magical, ‘what the actual f*** is this doing’ kind of way.

When you are in dev with Snowpack, you will not see files written. They are transformed (if needed) not onto the file system, but only in memory, for the browser to consume directly. This changes when you build (npx run build) – at that point Snowpack goes the extra distance and writes things into a build folder. But to keep things fast in dev land it doesn’t bother. That’s a good thing!

Snowpack mount options

By default, Snowpack will assume your entire project directory is a website, and will mount and scan the entire project for dependency imports. That may be what you want, but more likely you want some folders available but not others – maybe you have a folder for internal documentation for example, or a document with all the production site SQL database passwords as plain text – I’m JOKING! Don’t do that – I’m just checking you’re paying attention!! The point is we only want some folders ‘served’.

To facilitate this, when moving go Snowpack, I found it useful to reorganise things a little. Where, with Parcel, I had my authoring files in the root, and Parcel would dutifully create a dist folder to send the compiled and bundled output to, with Snowpack, I moved all my authoring files to a src folder.

Now, you might also want a folder for static assets, which I did, and called ‘public’ you can tell Snowpack to just serve that up ‘as is’ – that ‘public’ naming seems to be an established convention with the Snowpack examples I have looked at so I rolled with it. But be aware there isn’t a right way to organise and name things, just whatever works for you.

So to illustrate, my simplified setup for Snowpack I had this kind of file structure:

src/
  index.html
  styles.css
  app.ts
  interface/
    component-one/
      component-one.scss
      component-one.ts
    component-two/
      component-two.scss
      component-two.ts
  mockserver/
    server-responses.ts
    mock-data.json
public/

And here is a basic mount setup to achieve this:

mount: {
    public: { url: "/public", static: true },
    src: "/",
},

Couple of things worth noting. I’m using the expanded object notation for the public folder here. I want that in this case because static: true allows me to tell Snowpack that I don’t want anything in that folder transformed. The default for static is false.

So what this means in practice is if I have my index.html inside the src folder, and I want to path to a favicon, for example, that lives in the public then it needs to be written like this:

<link rel="icon" type="image/svg+xml" href="/public/faviconBF.svg">

The /public there in the link tag corresponds to the /public in the value of the public key of the mount object.

That means that when Snowpack is spun up with:

npx snowpack dev

The http://localhost:8080/ address is going to serve up the index.html correctly from the src folder and reference the assets in the public correctly.

Note that we’ve used a root relative link there for the icon. Hold on to that thought when we get to module importing in a moment.

The benefits of serving up your source files

I also found it useful with Snowpack that as it is serving up your source files, if you don’t want the hassle of JS routing for simple prototypes/POCs you can just use your source file structure. So, say I want a ‘benefits’ page, I can just create a benefits/index.html inside the src folder and link to that and I get a nice sensible url to navigate to and display e.g. http://localhost:8080/benefits/

If however you do want to use it with a SPA using a JS router, you probably want this in your snowpack.config.js file:

routes: [{ match: "routes", src: ".*", dest: "/index.html" }],

Which basically says, don’t do anything with any routes – just keep them on the index page.

That pretty much covers the basic principals of Snowpack, next I want to get into the nitty-gritty of some particulars. Things that differed when moving a codebase to Snowpack and some optimisations I think are worth making – in particular if you want nice and fast Sass compiles.

TypeScript. Without TypeScript

If you are coming from Parcel and writing in TypeScript, there’s a fair chance you will have a tsconfig.json file that TypeScript uses to build out your TypeScript. Well, you can likely just go ahead and delete that. Snowpack uses Babel to transform your TypeScript so it bypasses your typical TypeScript config – or worse, tries to do something with it, modules wise, based on that config file that no longer makes sense.

So the short version is, if you don’t need the sophistication of tsc doing the compiling, you link to your resultant JS file and Snowpack will have been smart enough to transform it for you via Babel which is considerably faster. You can tell it to compile with TSC but my TypeScript needs are so modest for the most part I can live without it.

Module resolution

Parcel forced me to start writing my JavaScript as modules. That improved things no end for me, even as someone rarely writing anything for a ‘production’ environment.

However, depending how you ‘pathed’ your modules in Parcel, getting them all to talk to one another in Snowpack land may be problematic. It was an easy but laborious fix in my case. The Parcel project I work on day to day has heaps of individual components, typically a JS/TS file alongside a CSS/Sass file. The HTMl side of things gets handled in the TS/JS by lit-html (which I still love BTW).

As there are nested components its typically been easiest to write import statements like this:

import { clone } from "~server/utilities/rfdc";

Using the tilde to reference the project root. But you don’t seem able to do root relative paths in Snowpack. Whether, I start them with a / or a tilde or the main folder, they just straight up don’t behave. Or at least that’s been my experience so far from failing to get them working and reading they didn’t work in the Snowpack Discord.

You need all your import paths to be written relative. So that prior import might need to be rewritten as:

import { clone } from "../../../server/utilities/rfdc";

And you can also use the current folder ./ type too. But no way, it seems, to write root relative paths. I can’t be sure, this may just be some config I have neglected to uncover. If someone knows otherwise, please enlighten me.

Honestly, this was the most time consuming part of the migration. With a hundred TypeScript files to ‘repath’ it was simple but tedious to fix.

Sass is straightforward, and can be fast

By default, Sass is slower to build in Node than the existing PostCSS CSS processing setup I had that was giving comparable functionality. However, Sass gives fewer setup and onboarding considerations. Less moving parts if you will. I’m all about less moving parts!

Sass is a simple addition to Snowpack. You just need to add it as a plugin:

npm i @snowpack/plugin-sass

Now, don’t stop there. Sass has a much faster, Dart based compiler Snowpack can use instead of the default npm based version.

Make Sass great again!

The Sass Snowpack plugin enables you to configure Snowpack to call out to the Dart Sass compiler. You’ll need to install the Dart compiler for Sass. I’m on macOS so used the Homebrew option:

 brew install sass/sass/sass

With that installed we can configure Snowpack to use Dart instead.

At this point, if you haven’t already, you will need to make a snowpack.config.js file, which you can do by running snowpack init. Here is how mine looks at this point:

module.exports = {
    mount: {
        public: { url: "/public", static: true },
        src: "/dist",
        /* ... */
        // static: { url: "/static", static: true, resolve: false },
    },
    plugins: ["@snowpack/plugin-sass"],

};

We need that plugin option amended to look something like this:

plugins: [
    [
        "@snowpack/plugin-sass",
        {
            native: true,
            compilerOptions: {
                style: "compressed",
            },
        },
    ],
],

Now, pay attention 007, notice the extra square brackets in there, around the plugin? Don’t forget those all you will get an error like, TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Object but obviously who would be so stupid as to miss those and spend 30 minutes trying to figure out why it isn’t working, right?

With that in place your Sass will be using Dart to compile, and your compiles will be fast and you will look upon your build tool and be happy(er).

You can see with that object we are also passing options to the Dart compiler; in this case I’m asking for the output to be compressed. You could just leave that bit out though if you’d rather.

Summary

Snowpack is a little bit of a sea-change from traditional build tools. Conceptually just a little to the left of what you are perhaps used to.

If you are starting a greenfield project I’d have zero qualms opting for Snowpack. It doesn’t have the depth of support documentation or stack overflow questions if you find yourself in the weeds, but generally speaking, it is solid enough to pick up and run with.

Migrating an existing project, which was setup for a different build tool, Parcel in my instance is, as expected, significantly more problematic.

I’m out the other side but I’ve not used Snowpack for long enough to judge categorically whether jumping onto Snowpack instead of continuing with Parcel was worth the hassle. Upgrading the same project to Parcel v2 was pretty straightforward in comparison.

But I do appreciate this subtle shift in tools like Snowpack that do as little as possible. I hope to see this trend continue. Next up, I’m off to give Vite a whirl.



Source link

r/graphic_design - First time designing a poster
Strategy

First time designing a poster : graphic_design


Hello there! This is my first time posting on reddit so excuse any mistakes and my broken English.

After saving a lot of inspiration and “things I’d like to do” on Pinterest and never doing them, I finally decided to give it a try and make my own poster for a song I like (I ended up doing one for the whole album though).

Even though I’ve used photoshop before to make small edits to photos, this is my first time trying all the other tools, especially the 3D tool to wrap the text around the disco ball.

Anyways, I wouldn’t like to make this any longer so I’ll leave the poster and I ask you all to give me any feedback. I’d gladly accept it!

r/graphic_design - First time designing a poster



Source link

Topframe | CSS-Tricks
Strategy

Topframe | CSS-Tricks


This is extremely fun. Jeff Lindsay has created Topframe, and writes:

Anybody that knows how to mess around with HTML can now mess around with their desktop computing experience. Topframe is an open source tool that lets you customize your desktop screen using HTML/CSS/JavaScript.

The default screen after installing has some hardcore weirdweb energy.

Mac-only I think for now.

But it’s super easy to customize. It’s just an index.html file at ~/.topframe/index.html. It auto-refreshes when you save the file.

My first thought was to fill my desktop with everything Dave likes from his RSS feed. But I tried dropping that JavaScript in and it didn’t work. I couldn’t debug it because there is no console to look at or anything. Oh well. I imagine practical use-cases include building little widgets with live data you want to keep an eye on at all times.

The other hiccup I had is that it messes with taking window screenshots. You know how you can go Command + Shift + 4 then Space on macOS to select just one window to screenshot? You can’t do that with this running because it’s always the top window. Hence “top frame” (get it?). I think it would be more fun to be “bottom frame” in that it would act more like a background instead of being always on top.

Apparently, Windows could do this a long time ago, proving (yet again) that there is nothing new under the sun.





Source link

A 3 by 3 grid of square cards with color backgrounds made from conic gradients. The gradients appear like stripes that extend from opposite corners of the card. Each card reads Hello Gorgeous in a fancy script font.
Strategy

Variable Aspect Ratio Card With Conic Gradients Meeting Alon…


I recently came across an interesting problem. I had to implement a grid of cards with a variable (user-set) aspect ratio that was stored in a --ratio custom property. Boxes with a certain aspect ratio are a classic problem in CSS and one that got easier to solve in recent years, especially since we got aspect-ratio, but the tricky part here was that each of the cards needed to have two conic gradients at opposite corners meeting along the diagonal. Something like this:

A 3 by 3 grid of square cards with color backgrounds made from conic gradients. The gradients appear like stripes that extend from opposite corners of the card. Each card reads Hello Gorgeous in a fancy script font.
User set aspect ratio cards.

The challenge here is that, while it’s easy to make an abrupt change in a linear-gradient() along the diagonal of a variable aspect ratio box using for example a direction like to top left which changes with the aspect ratio, a conic-gradient() needs either an angle or a percentage representing how far it has gone around a full circle.

Check out this guide for a refresher on how conic gradients work.

The simple solution

The spec now includes trigonometric and inverse trigonometric functions, which could help us here — the angle of the diagonal with the vertical is the arctangent of the aspect ratio atan(var(--ratio)) (the left and top edges of the rectangle and the diagonal form a right triangle where the tangent of the angle formed by the diagonal with the vertical is the width over the height — precisely our aspect ratio).

Illustration. Shows a rectangle of width w and height h with a diagonal drawn from the bottom left corner to the top right one. This diagonal is the hypotenuse of the right triangle whose catheti are the left and top edges of the rectangle. In this right triangle, the tangent of the angle between the hypotenuse (diagonal of original rectangle) with the vertical (left edge of original rectangle) is the top edge (w) over the left edge (h).
The angle of the diagonal with the vertical (edge).

Putting it into code, we have:

--ratio: 3/ 2;
aspect-ratio: var(--ratio);
--angle: atan(var(--ratio));
background: 
  /* below the diagonal */
  conic-gradient(from var(--angle) at 0 100%, 
      #319197, #ff7a18, #af002d  calc(90deg - var(--angle)), transparent 0%), 
  /* above the diagonal */
  conic-gradient(from calc(.5turn + var(--angle)) at 100% 0, 
      #ff7a18, #af002d, #319197 calc(90deg - var(--angle)));

However, no browser currently implements trigonometric and inverse trigonometric functions, so the simple solution is just a future one and not one that would actually work anywhere today.

The JavaScript solution

We can of course compute the --angle in the JavaScript from the --ratio value.

let angle = Math.atan(1/ratio.split("https://css-tricks.com/").map(c => +c.trim()).reduce((a, c) => c/a, 1));
document.body.style.setProperty('--angle', `${+(180*angle/Math.PI).toFixed(2)}deg`)

But what if using JavaScript won’t do? What if we really need a pure CSS solution? Well, it’s a bit hacky, but it can be done!

The hacky CSS solution

This is an idea I got from a peculiarity of SVG gradients that I honestly found very frustrating when I first encountered.

Let’s say we have a gradient with a sharp transition at 50% going from bottom to top since in CSS, that’s a gradient at a angle. Now let’s say we have the same gradient in SVG and we change the angle of both gradients to the same value.

In CSS, that’s:

linear-gradient(45deg, var(--stop-list));

In SVG, we have:

<linearGradient id='g' y1='100%' x2='0%' y2='0%' 
                gradientTransform='rotate(45 .5 .5)'>
  <!-- the gradient stops -->
</linearGradient>

As it can be seen below, these two don’t give us the same result. While the CSS gradient really is at 45°, the SVG gradient rotated by the same 45° has that sharp transition between orange and red along the diagonal, even though our box isn’t square, so the diagonal isn’t at 45°!

Screenshot. Shows a rectangle with a CSS gradient at 45° (left) vs. a rectangle with a bottom to top SVG gradient rotated by 45° (right). This angle is adjustable via the slider at the bottom. The CSS gradient is really at 45°, but the line of the SVG gradient is perpendicular onto the rectangle's diagonal.
45° CSS vs. SVG gradient (live demo).

This is because our SVG gradient gets drawn within a 1x1 square box, rotated by 45°, which puts the abrupt change from orange to red along the square diagonal. Then this square is stretched to fit the rectangle, which basically changes the diagonal angle.

Note that this SVG gradient distortion happens only if we don’t change the gradientUnits attribute of the linearGradient from its default value of objectBoundingBox to userSpaceOnUse.

Basic idea

We cannot use SVG here since it only has linear and radial gradients, but not conic ones. However, we can put our CSS conic gradients in a square box and use the 45° angle to make them meet along the diagonal:

aspect-ratio: 1/ 1;
width: 19em;
background: 
  /* below the diagonal */
  conic-gradient(from 45deg at 0 100%, 
      #319197, #ff7a18, #af002d 45deg, transparent 0%), 
  /* above the diagonal */
  conic-gradient(from calc(.5turn + 45deg) at 100% 0, 
      #ff7a18, #af002d, #319197 45deg);

Then we can stretch this square box using a scaling transform – the trick is that the ‘/’ in the 3/ 2 is a separator when used as an aspect-ratio value, but gets parsed as division inside a calc():

--ratio: 3/ 2;
transform: scaley(calc(1/(var(--ratio))));

You can play with changing the value of --ratio in the editable code embed below to see that, this way, the two conic gradients always meet along the diagonal:

Note that this demo will only work in a browser that supports aspect-ratio. This property is supported out of the box in Chrome 88+ (current version is 90), but Firefox still needs the layout.css.aspect-ratio.enabled flag to be set to true in about:config. And if you’re using Safari… well, I’m sorry!

Screenshot showing how to enable the Firefox flag. Go to about:config (type that in the address bar - you may be asked if you're sure you want to mess with that stuff before you're allowed to enter). Use the search bar to look for 'aspect' - this should be enough to bring up the flag. Set its value to true.
Enabling the flag in Firefox.

Issues with this approach and how to get around them

Scaling the actual .card element would rarely be a good idea though. For my use case, the cards are on a grid and setting a directional scale on them messes up the layout (the grid cells are still square, even though we’ve scaled the .card elements in them). They also have text content which gets weirdly stretched by the scaley() function.

Screenshot. Shows how the card elements are scaled down vertically, yet the grid cells they're occupying have remained square, just like the cards before the directional scaling.

The solution is to give the actual cards the desired aspect-ratio and use an absolutely positioned ::before placed behind the text content (using z-index: -1) in order to create our background. This pseudo-element gets the width of its .card parent and is initially square. We also set the directional scaling and conic gradients from earlier on it. Note that since our absolutely positioned ::before is top-aligned with the top edge of its .card parent, we should also scale it relative to this edge as well (the transform-origin needs to have a value of 0 along the y axis, while the x axis value doesn’t matter and can be anything).

body {
  --ratio: 3/ 2;
  /* other layout and prettifying styles */
}

.card {
  position: relative;
  aspect-ratio: var(--ratio);

  &::before {
    position: absolute;
    z-index: -1; /* place it behind text content */

    aspect-ratio: 1/ 1; /* make card square */
    width: 100%;
    	
    /* make it scale relative to the top edge it's aligned to */
    transform-origin: 0 0;
    /* give it desired aspect ratio with transforms */
    transform: scaley(calc(1/(var(--ratio))));
    /* set background */
    background: 
      /* below the diagonal */
      conic-gradient(from 45deg at 0 100%, 
      #319197, #af002d, #ff7a18 45deg, transparent 0%), 
      /* above the diagonal */
      conic-gradient(from calc(.5turn + 45deg) at 100% 0, 
      #ff7a18, #af002d, #319197 45deg);
    content: '';
  }
}

Note that we’ve moved from CSS to SCSS in this example.

This is much better, as it can be seen in the embed below, which is also editable so you can play with the --ratio and see how everything adapts nicely as you change its value.

Padding problems

Since we haven’t set a padding on the card, the text may go all the way to the edge and even slightly out of bounds given it’s a bit slanted.

Screenshot. Shows a case where the text goes all the way to the edge of the card and even goes out a tiny little bit creating an ugly result.
Lack of padding causing problems.

That shouldn’t be too difficult to fix, right? We just add a padding, right? Well, when we do that, we discover the layout breaks!

Animated gif. Shows the dev tools grid overlay t highlight that, while the background (created with the scaled pseudo) still has the desired aspect ratio, the grid cell and the actual card in it are taller.
Adding a padding breaks the layout. (Demo)

This is because the aspect-ratio we’ve set on our .card elements is that of the .card box specified by box-sizing. Since we haven’t explicitly set any box-sizing value, its current value is the default one, content-box. Adding a padding of the same value around this box gives us a padding-box of a different aspect ratio that doesn’t coincide with that of its ::before pseudo-element anymore.

In order to better understand this, let’s say our aspect-ratio is 4/ 1 and the width of the content-box is 16rem (256px). This means the height of the content-box is a quarter of this width, which computes to 4rem (64px). So the content-box is a 16rem×4rem (256px×64px) rectangle.

Now let’s say we add a padding of 1rem (16px) along every edge. The width of the padding-box is therefore 18rem (288px, as it can be seen in the animated GIF above) — computed as the width of the content-box, which is 16rem (256px) plus 1rem (16px) on the left and 1rem on the right from the padding. Similarly, the height of the padding-box is 6rem (96px) — computed as the height of the content-box, which is 4rem (64px), plus 1rem (16px) at the top and 1rem at the bottom from the padding).

This means the padding-box is a 18rem×6rem (288px×96px) rectangle and, since 18 = 3⋅6, it has a 3/ 1 aspect ratio which is different from the 4/ 1 value we’ve set for the aspect-ratio property! At the same time, the ::before pseudo-element has a width equal to that of its parent’s padding-box (which we’ve computed to be 18rem or 288px) and its aspect ratio (set by scaling) is still 4/ 1, so its visual height computes to 4.5rem (72px). This explains why the background created with this pseudo — scaled down vertically to a 18rem×4.5rem (288px×72px) rectangle — is now shorter than the actual card — a 18rem×6rem (288px×96px) rectangle now with the padding.

So, it looks like the solution is pretty straightforward — we need to set box-sizing to border-box to fix our problem as this applied the aspect-ratio on this box (identical to the padding-box when we don’t have a border).

Sure enough, this fixes things… but only in Firefox!

Screenshot collage. Shows how the text is not middle aligned in Chromium browsers (top), while Firefox (bottom) gets this right.
Showing the difference between Chromium (top) and Firefox (bottom).

The text should be middle-aligned vertically as we’ve given our .card elements a grid layout and set place-content: center on them. However, this doesn’t happen in Chromium browsers and it becomes a bit more obvious why when we take out this last declaration — somehow, the cell in the card’s grid gets the 3/ 1 aspect ratio too and overflows the card’s content-box:

Animated gif. For some reason, the grid cell inside the card gets the set aspect ratio and overflows the card's content-box.
Checking the card’s grid with vs. without place-content: center.

Fortunately, this is a known Chromium bug that should probably get fixed in the coming months.

In the meantime, what we can do to get around this is remove the box-sizing, padding and place-content declarations from the .card element, move the text in a child element (or in the ::after pseudo if it’s just a one-liner and we’re lazy, though an actual child is the better idea if we want the text to stay selectable) and make that a grid with a padding.

.card {
  /* same as before, 
     minus the box-sizing, place-content and padding declarations 
     the last two of which which we move on the child element */
  
  &__content {
    place-content: center;
    padding: 1em
  }
}

Rounded corners

Let’s say we also want our cards to have rounded corners. Since a directional transform like the scaley on the ::before pseudo-element that creates our background also distorts corner rounding, it results that the simplest way to achieve this is to set a border-radius on the actual .card element and cut out everything outside that rounding with overflow: hidden.

Screenshot. Shows an element that's not scaled at all on the left. This has a perfectly circular border-radius. In the right, there's a non-uniform scaled element - its border-radius is not perfectly circular anymore, but instead distorted by the scaling.
Non-uniform scaling distorts corner rounding. (Demo)

However, this becomes problematic if at some point we want some other descendant of our .card to be visible outside of it. So, what we’re going to do is set the border-radius directly on the ::before pseudo that creates the card background and reverse the directional scaling transform along the y axis on the y component of this border-radius:

$r: .5rem;

.card {
  /* same as before */
  
  &::before {
    border-radius: #{$r}/ calc(#{$r}*var(--ratio));
    transform: scaley(calc(1/(var(--ratio))));
    /* same as before */
  }
}

Final result

Putting it all together, here’s an interactive demo that allows changing the aspect ratio by dragging a slider – every time the slider value changes, the --ratio variable is updated:





Source link

r/web_design - HTML/CSS Help. Sideways Vertical Menu
Strategy

HTML/CSS Help. Sideways Vertical Menu : web_design


All, Thank you for a awesome community. I’ve learned a lot from you all from lurking.

I have a project that I have a draft example of a vertical menu but it is turned on it side.

r/web_design - HTML/CSS Help. Sideways Vertical Menu

The concept of this menu is that it would work like a book and that you would “turn the pages” to load a different page by click on it. I have ambitions to add an animation but need to figure out how to get the code to set the element as fixed, to the left and fill the height of the page minus the header.

The issue I run into is that when the element is turned 90 degs, it still keep the width of the page and then moves to the center. I’m guessing that is due to Transform rotating it by the center of the element.

Below is my code exmaples.

HTML Code:

<div class="menu">
<ul>
    <li class="menuButton1">
        <a href="#">Home</a>
    </li>
    <li class="menuButton2">
        <a href="#">Contact</a>
    </li>
    <li class="menuButton3">
        <a href="#">Shop</a>
    </li>
    <li class="menuButton4">
        <a href="#">About</a>
    </li>
 </ul>
</div>    

CSS Code:

nav { 
  padding-top: 36px; 
  } 
nav .menu { 
  position: fixed; 
  transform: rotate(90deg); 
  top: 0; left:0; width: 100%; 
  } 

nav .menuButton1 {
  background-color: #ff2929; 
  }
nav .menuButton1 a {
  color: white; 
  }

nav .menuButton2 { 
  background-color: #ffd429; 
  }
nav .menuButton2 a {
  color: white; 
  }

nav .menuButton3 {
  background-color: #00abd4;
  } 
nav .menuButton3 a {
  color: white;
  }

My thoughts while writing this:

Do I need to make two different elements? One that is the actual block and background color and then have the text rotate 90 Degs?
Should I use something to figure out the height of the screen and write it as the width and move it somehow to the left?

Please let me know how you would do this or if there is something I’m missing.

Thanks!



Source link

React.js More Popular Than Angular
Strategy

React vs. Angular: Who Wins the Competition?


Choosing the Best Option for Front-End Development

React.js vs. Angular. They are equally good at building web-based applications. Some of the world’s projects are built with React.js, others of the same size, with Angular.

These examples emphasizing both React.js and Angular are suited for making large and scalable platforms, handling massive requests per moment.

Current Statistics by Popularity

React.js gets on the top position and overruns Angular with the number of Node Package Manager (NPM) downloads on GitHub. The difference is huge.

Last year’s survey among Stackoverflow’s users demonstrates that React.js is 10% more popular than Angular.

React.js More Popular Than Angular

Does it mean that something goes wrong with Angular? Or, does it imply React.js offered better solutions than Angular?

Main Principles of Angular

Let’s figure it out by overviewing both systems in a nutshell. Angular originates from the startup products of Google, where the key of product development was to manage multiple processes in one place. Any unreasonable decision could lead to a problem and affect billions of user operations run in a moment.

Angular became a monolithic framework that predefined programming steps. Even though it enriches the development process with the services, controllers, and modules, it dictates its own way of thinking and working. That places a distance between programmer and framework.

Along with that, there are a few other factors that make Angular less accessible: 

  1. Angular uses object-oriented programming (OOP), so its knowledge is hard-skill.
  2. Developers should have a good command of TypeScript.
  3. Knowledge of RxJS is a must-have too.

Apparently, the learning curve is very high. Unlike React.js, Angular demands more OOP-related experience from developers. That worked for Google, considering their team’s high expertise. Angular was envisioned as an end-to-end solution and was compatible with their advanced programming culture.

Despite the complexity of the architecture, Angular has its indisputable benefits:

  • Two-way data binding automates synchronization between the Model and the View. Say, if the data was changed in the Model, it would be changed automatically in the View (DOM). Such a function takes off the need to write more additional code. Just imagine Google Drive’s document, as a user types text in the document, it is viewed by another one in real-time. Such a function is possible due to the two-way data binding.
  • Dependency injection (DI), makes it possible to deliver the dependency from one to another class. Due to DI, server-side services could be delegated to a client-side. So, it is a serious advantage of OOP usage in Angular.
  • Directives aimed to enrich the HTML by providing a new syntax to it. The most common directive is the component. Using it, programmers could create any attribute for an existing element and change its behavior. This is a helpful feature, which makes working with the DOM very flexible.

Angular is enriched with many other valuable features, like UI Material, making it possible to reuse the code of components in other parts of the project, but this is similar to what React offers too.

Who Chooses Angular Today?

Experienced front-end developers share that Angular fits well with enterprise solutions and the corporate sector when React.js is a better choice for early-stage startups and smaller companies. This could be explained that big business does not change their priorities very often and the strategic goals are known to their CTOs far earlier.

The main point you could take from our overview is to remember that Angular is a better option for long-term projects requiring reliability above anything else. Besides others mentioned in the list, a few more companies are using Angular: Microsoft Office, Deutsche Bank, and Samsung.

React.js even doesn’t call itself a framework but a JS library. Unlike Angular, React.js makes it a developer’s responsibility to set a project structure, find relevant services for HTTP routing, and so on. At this point, React’s ideology is to be agile and provide developers with absolute freedom. As a result, it leads to minimizing the project’s size from start, as they could involve those libraries that they need by a certain time.

Let’s imagine that you are the only front-end developer on the project, or there are just a few. The main goals are set for the shortest perspective here. You should be both fast and productive, be able to adjust to startup goals. The straight rules and architecture demands of Angular will slow down the process of development.

So, following single policies is not a major priority for the React.js community. In fact, this is straight opposite to Angular.

It is worth mentioning, React.js couldn’t work alone, as it is only the View (V) and needs an engine for data processing. A developer needs to figure out its implementation, manage with Redux and Saga, and arrange that individually.

What makes React.js Different?

  • The learning curve is low. A developer with HTML and JavaScript experience could take on web development and show their first outcomes soon.
  • The architecture is simple and doesn’t take much time to study all its structure.
  • Virtual DOM made server-side rendering less time-consuming.
  • Huge community support that regularly contributes to React.js collection.
  • Intuitive environment, pleasant interface to work with.

What problem does virtual DOM solve?

The current situation is next: if anything has been changed in a user browser while clicking on a page, these changes will be automatically recorded to the DOM. To show the changes on the web page, the browser should reload the entire DOM structure. It brings more loads to the browser and slows down the performance of the application.

React.js Innovations in Performance

  • React.js creates a snapshot of the DOM, which is named the virtual DOM (VDOM).
  • Every new change in the UI component is to be recorded to the new virtual DOM first, not the regular one.
  • React.js compares the new version of the VDOM and determines if those changes were essential to update the browser’s DOM.
  • If the changes were essential, React.js updates the DOM with the latest portion of changes.

React.js has such computing algorithms that allow it to decide when to update the DOM in the browser. That makes front-end applications very performative. Unlucky, Angular doesn’t have anything similar to this feature.

React.JS Approach in HTML RenderingWith that said, React.js helps to write clean JavaScript code for the projects when Angular complements the HTML with many extensions. This becomes messy in a while and hard to deal with such an enlarged code.

It is time to say: React.js dominates in the front-end development area today.

Advanced features, ease of use, extensive collection of javascript libraries placed React.js in a higher position than Angular. That proves an idea that the user-centered approach is a king. React.js has become an intuitive and powerful resource for making front-end applications.

The discussions like ‘Angular vs. React’ are obviously coming to an end because of the React.js win. Nowadays, the community is much interested in other frameworks like Vue.js, and comparison of that kind will be more actual today.



Source link

Created 2 JavaScript Files
Strategy

Node.js – Dependency Management – DZone Web Dev


Introduction

An important concept in Node.js is that you want to know the way dependency management is handled. This dependency management is part of the core Node.js experience. In this post, we will learn the various patterns of dependency management and how Nodejs load dependencies.

So, we could write our application using a single js file for everything, but that’s not modular. Node.js makes it very simple to write modular code.

Before we dive into the details, the first question to answer, the module. What is it? And why should we care about it?

In simple terms, a module is a code, that we group together, for the purposes of sharing and reuse. Modules, therefore, allow us to break down complexity in our applications into small chunks. This can help with understanding the code right down to finding and fixing bugs. If you want to know more about JavaScript Module systems, you can check this post.

Node uses a facility for requiring certain behaviors. This is based on CommonJS. In short, to bring a JavaScript file, we use the keyword require.

I am assuming that you already know some basics of Nodejs. You can also check my earlier post Node.js – Introduction for some background information if you are new to Nodejs.

Setting Up the Application

Let’s start simple. I’ve created a directory for the project, used npm init to initialize it, and created two JavaScript files (app.js and appMsg.js). This is how to project looks like and we will use this as a starting point for the demos. Also, you can download the final code from the git repo link mentioned later in the post.

Created 2 JavaScript Files

At this point, both .js files are empty. Let’s update appMsgs.js file with the following changes:
Updating appMsgs.js

We can see the use of the module.exports keyword. This syntax is used to expose properties or objects from a given file (appMsgs.js) which can be then used in another file and in our case that will be app.js.

In this system, each file has access to something called the module.exports. So, we exposed some items in the appMsgs.js file and now Let’s see how app.js can use (require) these properties:

Adding Require

Now to reference a file, we use the require keyword. When we require, it is going to return an object that’s going to represent that modular piece of code, so we assign this to a variable appMsgs variable and then simply used properties in console.log statements. When we execute the code, we can see the following output:

Code Execution Output

So, this require is executing the JavaScript, allowing it to construct an object that had returned to us has some functionality.

This could be a class constructor or an object that has a number of elements in it or some plain simple properties. There are different patterns for this and we can export more than one thing or even export complex objects.

So by managing require, as well as module.exports, we can create these modular applications.

The required functionality loads the code and loads it once. So, whatever code is executed here, this is never executed a second time. So, if someone else asked for this object by require, it’s going to get a cached version of this. Let’s look at some other ways.

Exporting a Function

I have changed the code and now instead of exposing an object, it is exporting a function. This code is executed every time when called as a function.

Let’s see how it is used in app.js file next:

Updating app.js File

Instead of calling a property, we can just execute it, like a function. So, the difference here is that every time we execute this code, the code inside the function is re-executed.

Here is the output when we run the code:
New Execution Output

So, we have seen two patterns of module.exports and their difference. Another common pattern, you’re going to want to be aware of using this as a constructor method. Let’s see an example of that:

Constructor Method

and here is the updated app.js file:
New Update to app.js File

So, this is in essence is the same thing as when you’re creating a pseudo-class in JavaScript and allowing you to create instances of it.

Here is the output of this change:

Output of Most Recent Change

Now, let’s see another example of these patterns:

I have created a new file called userRepo.js as follows:

userRepo.js

And here is app.js and execution result for this change:

Change to app.js for New File Creation

New File Execution Result

Using require for individual files is not uncommon but there is also another pattern you should be aware of. Let’s see folder dependencies next.

Folder Dependency

We will take a step back and understand how Nodejs looks for dependencies. Remember the line from earlier examples:

Node would still look for appMsgs.js file, but also it would look for appMsgs as a directory and whichever it found first, it would pull that in.

Now let’s see the code:

I have created a folder called logger and inside that folder, I created a file index.js.

Here is the code from index.js file:

Code from index.js

And here is the app.js file which requires this module:

app.js File Which Requires This Module

So, in our case we could say:

And that would be perfectly valid. But instead, by just saying the following:

Since there isn’t a logger.js, there’s a logger directory, it’s going to by default load the index.js as the starting point for our logger. That’s why I gave the name index.js and let’s see what is the result of executing this code:

Result of Adding index.js

So, on its own, you might think, well why bother going through this extra step of creating a folder and an inex.js?

And the reason for that is you may be putting together a complex dependency and this dependency may have other pieces it depends on. The caller that needs the logger doesn’t need to know that there’s a bunch of these other dependencies.

This is a form of encapsulation so that as we are building more complex pieces, we can build them out of multiple files. Then on the consumer side, use a single file. It just implies that a folder is a good way to manage those sorts of dependencies.

Node Package Manager (NPM)

One more thing we want to discuss briefly is NPM. You might already know its purpose. This brings in additional functionality and its usage is very straightforward.

We can install a dependency using npm:

npm install underscore;

And then can simply require it in app.js as follows:

Require NPM in app.jsAnd you can see how we can use functionality offered by the underscore package. Also when we required this module, we didn’t specify the file path, we just use its name and Nodejs will load this module from the node_modules folder in your application.

Underscore Example

Here is the output of the execution:
Output of Final Execution

Summary

In this post, we learned how Nodejs manage its dependencies and we saw few patterns to use in our application. You can download the source code from this Git repository. Let me know if you have any questions or comments. Till next time, Happy Coding!



Source link