Organizing HTML, CSS, and JS to Create Modular Website Components

Most websites contain the same or very similar layouts on multiple pages, e.g. header and footer. There also might be a few different hero section designs and a few different CTA section designs. Imagine having 10 product pages each containing three 2-column sections with a text description in the left column and a screenshot in the right column. Each of these product pages may also have a CTA section design but with slightly different text and links. It’s common to put shared CSS in a shared CSS file, e.g. shared.css, common.css, or global.css. This especially makes sense for the header and footer, which are usually shown on all pages. But over time, that shared CSS file can become very long because you may have a lot of CSS for many different common sections. This can make it difficult and dangerous to edit code for just one particular section. It can also make it very difficult if you want to copy a section on one page to add to another page. If the HTML, CSS, and JS for the section aren’t isolated, you may not copy all the necessary code, not to mention you could end up with inconsistencies between two or more sections that should have the same design.

Consolidating all CSS into the fewest files possible is good for website performance (the fewer files, the fewer network requests), but nowadays, it’s common for websites, including simple static websites, to go through an automated build process to optimize the files before publishing them. The build process can do many things like minify and combine multiple CSS and JS files into single CSS and JS files, add prefixes to CSS using tools like PostCSS auto-prefixer, etc.

Following is one simple approach to grouping HTML, CSS and JS by website section. This approach can also be used for any part of a website like blocks within a section, but to keep things simple, we’ll just look at sections which I define as horizontal rows of related content, e.g.

  • header section
  • hero section design 1
  • hero section design 2
  • features section design 1
  • features section design 2
  • resources section
  • CTA section
  • footer section

Here’s one possible file structure:

my-website/
├─ src/
│  ├─ index.njk
│  ├─ index.css
│  ├─ index.js
│  ├─ product1/
│  │  ├─ index.njk
│  │  ├─ index.css
│  │  ├─ index.js
│  ├─ product2/
│  │  ├─ index.njk
│  │  ├─ index.css
│  │  ├─ index.js
│  ├─ components/
│  │  ├─ header/
│  │  │  ├─ header.njk
│  │  │  ├─ header.css
│  │  │  ├─ header.js
│  │  ├─ footer/
│  │  │  ├─ footer.njk
│  │  │  ├─ footer.css
│  │  │  ├─ footer.js
│  │  ├─ section1/ (e.g. hero layout design 1)
│  │  │  ├─ section1.njk
│  │  │  ├─ section1.css
│  │  │  ├─ section1.js
│  │  ├─ section2/ (e.g. hero layout design 2)
│  │  │  ├─ section2.njk
│  │  │  ├─ section2.css
│  │  │  ├─ section2.js
│  │  ├─ section3/ (e.g. features layout design 1)
│  │  │  ├─ section3.njk
│  │  │  ├─ section3.css
│  │  │  ├─ section3.js
│  │  ├─ section4/ (e.g. CTA layout design 1)
│  │  │  ├─ section4.njk
│  │  │  ├─ section4.css
│  │  │  ├─ section4.js
├─ build/
│  ├─ index.html
│  ├─ index.css
│  ├─ index.js
│  ├─ product1/
│  │  ├─ index.html
│  │  ├─ index.css
│  │  ├─ index.js
│  ├─ product2/
│  │  ├─ index.html
│  │  ├─ index.css
│  │  ├─ index.js

In the src (source) folder, I’m using Nunjucks (njk) files instead of HTML files so they can include logic and pull in the components (partials). When the source files are processed, the built files show up in the “build” folder. For the home page source file (index.njk), the structure of the code could be like this

<html>
<head>

    {% include "/src/components/header/header.css" %}
    {% include "/src/components/footer/footer.css" %}
    {% include "/src/index.css" %}
</head>
<body>
    {% include "/src/components/header/header.njk" %}

    ... some HTML ...
    
    {% include "/src/components/footer/footer.njk" %}

    {% include "/src/components/header/header.js" %}
    {% include "/src/components/footer/footer.js" %}
    {% include "/src/index.js" %}
</body>
</html>

Note that the home page has its own CSS and JS files for elements that are not part of a component. When this file is built, the CSS and JS files will be combined (Netlify can do this automatically) and the included header and footer njk references will be replaced with their contents, e.g.

<html>
<head>
    <link rel="stylesheet" href="index-435kl3jl3j.css">
</head>
<body>
    <header>
        <p>FOO Website</p>
        <ul>
            <li>Home</li>
            <li>Product 1</li>
            <li>Product 2</li>
        </ul>
    </header>

    ... some HTML ...
    
    <footer>
        Copyright 2023
    </footer>

    <script src="index-43533lj344.js"></script>
</body>
</html>

Here’s another example. For product page 1 (product1/index.njk), the file contents may look like this

<html>
<head>

    {% include "/src/components/header/header.css" %}
    {% include "/src/components/section1/section1.css" %}
    {% include "/src/components/section4/section4.css" %}
    {% include "/src/components/header/footer.css" %}
    {% include "/src/product2/index.css" %}
</head>
<body>
    {% include "/src/components/header/header.njk" %}

    {% set title = "Product 1" %}
    {% set heroImage = "product1.jpg" %}
    {% include "/src/components/section1/section1.njk" %}

    ... some HTML ...

    {% set text = "Try Product 1 Now" %}
    {% set link = "/product1/free-trial/" %}
    {% include "/src/components/section4/section4.njk" %}
    
    {% include "/src/components/footer/footer.njk" %}

    {% include "/src/components/header/header.js" %}
    {% include "/src/components/section1/section1.js" %}
    {% include "/src/components/section4/section4.js" %}
    {% include "/src/components/footer/footer.js" %}
    {% include "/src/product2/index.js" %}
</body>
</html>

In the code example above, we’re passing some variables into components section1 and section 4. That allows us to reuse a component’s layout and design while changing its content. Since product pages usually look very similar, the code for product2/index.njk might look like this

<html>
<head>

    {% include "/src/components/header/header.css" %}
    {% include "/src/components/section1/section1.css" %}
    {% include "/src/components/section4/section4.css" %}
    {% include "/src/components/header/footer.css" %}
    {% include "/src/product2/index.css" %}
</head>
<body>
    {% include "/src/components/header/header.njk" %}

    {% set title = "Product 2" %}
    {% set heroImage = "product2.jpg" %}
    {% include "/src/components/section1/section1.njk" %}

    ... some HTML ...

    {% set text = "Try Product 2 Now" %}
    {% set link = "/product2/free-trial/" %}
    {% include "/src/components/section4/section4.njk" %}
    
    {% include "/src/components/footer/footer.njk" %}

    {% include "/src/components/header/header.js" %}
    {% include "/src/components/section1/section1.js" %}
    {% include "/src/components/section4/section4.js" %}
    {% include "/src/components/footer/footer.js" %}
    {% include "/src/product2/index.js" %}
</body>
</html>

I reused the components but changed the value of the variables that are referenced in the components.

To prevent code conflicts, you can specify an ID in the first element of each component. For example,

section1.njk

<div id="section1">
    ... some HTML ...
</div>

section2.njk

<div id="section2">
    ... some HTML ...
</div>

Then, in the component’s CSS, to prevent CSS conflicts, you can prefix all rules like this

section1.css

#section1 .intro {
    ... some CSS ...
}

#section1 .features {
    ... some CSS ...
}

section2.css

#section2 .intro {
    ... some CSS ...
}

#section2 .features {
    ... some CSS ...
}

Similarly, with the JavaScript component file, you can do something similar, e.g.

section1.js

$("#section1 .intro")...

section2.js

$("#section2 .intro")...

Another benefit of this approach is you can create a page showing a preview of all components you have. When you want to create a new page, you can browse the list of component previews to see if you can reuse an existing component or decide if you need to create a new component.

Pasta with Keto Bread: Quick, Low-Calorie Stomach Filler

I came across this sample food at Costco. It was Kirkland Organic Marinara from Tuscany dipped in ciabatta bread. It was surprisingly good, but the ciabatta bread was high in calories and not keto. So, here’s a keto version that is super quick to make and can fill you up in a jiffy.

Ingredients

  • Artisan Bakery Sonoma County Keto Bread (available at Costco)
  • Kirkland Organic Marinara from Tuscany

Instructions

  1. Heat up some of the marinara in a microwave
  2. Toast the bread slices to your desired toastiness
  3. Spoon the marinara onto the bread slices
  4. Eat

It’s like eating a healthy pizza without the high-calorie cheese. Four slices followed by a glass or two of water will make you feel satiated while only consuming less than 200 calories!

Keto, Low-Calorie Burger Recipe

Bun – 6 grams of carbs, 80 calories

A traditional burger bun like Artesano bakery bun contains 34 grams of net carbs and 190 calories. Replace that with an Orowheat Keto bun, which contains only 6 net carbs and 80 calories.

Beef Patty – 140 calories

A traditional beef patty like Costco’s Kirkland Signature Ground 1/3-lb (151 grams) Beef Patties contains 440 calories. Replace that with Smart ‘n Final’s First Street 96/4 (96% lean, 4% fat) 1/3-lb beef patties, which contain only 140 calories each.

Ketchup

Traditional ketchup like Heinz tomato ketchup contains 5 carbs and 20 calories per tablespoon. Replace that with Heinz tomato ketchup with no sugar added, which contains only 1 gram of carbs and 10 calories per tablespoon.

Cheese

A regular slice of cheddar cheese like Sargento’s cheddar cheese slices contains 80 calories. Replace that with something like Sargento’s reduced fat cheddar cheese slices, which contains only 60 calories per slice.

Or, go with slim-cut mozzarella cheese slices, which are only 35 calories per slice.

Or, just skip the cheese altogether.

Total Calories: 250

Create an Animated Travel Map Route with Pinnacle Studio

In this tutorial, I will explain how to create an animated travel map route from point A to point B using Pinnacle Studio.

1. Create two map images

We’re going to need to create 2 images.

  1. an image without a route
  2. an image with a route

This tutorial assumes you know how to create such images. I took a screenshot of Google Maps for the map background and used Photoshop to add balloon markers and location labels and to create the smooth route curves.

map-driving-route.png
map-driving-route-lax-griffith-w-line.png

2. Add images to video tracks

  • Open Pinnacle Studio
  • Click the Edit tab
  • Click the Library tab
  • Drag the two images to the library pane

Then, drag

  • the image with the line to AV track 1
  • the image without the line to AV track 2

By default, the clips will be 3 seconds long. I prefer to drag them so they are 10 seconds long.

3. Create the animation

  • Drag the playhead to the beginning of the image clips
  • Double-click on the image on AV track 1
  • Click the “Effect” tab
  • Click the “2D-3D” tab
  • Double-click “2D Editor Advanced”
  • For “Select Preset”, choose “No Preset”

Scroll down. Under “Cropping, we’re going to edit the cropping properties as follows:

  • if the line will mostly animate toward the bottom, drag the Top % slider until the line first completely disappears.
  • if the line will mostly animate toward the top, drag the Bottom % slider until the line first completely disappears.
  • if the line will mostly animate toward the right, drag the Left % slider until the line first completely disappears.
  • if the line will mostly animate toward the left, drag the Right % slider until the line first completely disappears.

The clip in AV track 1 shows a black mask partially covering the image as you drag the slider.

Drag the slider, you’ll notice the line starts to disappear in the preview window.

Scroll back up in the 2D Editor Advanced pane and click on the diamond icon to turn on keyframing.

  • Drag the playhead to the point on the clip where you want the line to be finished. This will also change the speed of the “animation” as the cropping will go quicker if you end it earlier. I just dragged it to near the end of the clip.
  • Scroll back down and drag the slider to the left until the line first appears in full
  • Preview the animation in the preview window.
  • If the animation looks good, you can export it.

One idea is to partially overlay a video clip of you driving while describing your trip.

Another idea is to overlay the map route animation at 50% opacity over a video of the trip.

In the example above, I used the following two images.

sf-la-without-line.png
sf-la-with-line.png

To create the composite video, I used Corel VideoStudio and put the route animation video on an overlay track.

Double-clicking the overlay clip opens the clip’s settings. I clicked the “Blending” tab and then set the opacity to 50%.

I then had to slow down the speed of the route animation so its duration would be close to or match that of the airplane clips.

  • Right-click on the route animation clip
  • Speed > Speed/Time-lapse…
  • Change duration (in my case, I chose 20 seconds)

UPDATE

It’s actually easier to create the route animation on a Mac using Keynote. See these video tutorials.

Map Resources

Screen Record and Resize a YouTube Video (Or Any Video on Screen)

Sometimes, you can download a YouTube video using a tool like YouTube-DLG or an online YouTube to MP4 converter. However, this doesn’t always work. One workaround is to use a screen recorder to record the video as it’s playing on YouTube in a browser. However, if you do this, then depending on various factors including the original video and your screen’s resolution, YouTube may show black bars around the video, like this

This tutorial for Windows will explain how to

  1. screen record a YouTube video
  2. resize the recorded video to remove the black bars

Screen Record a YouTube Video

There are many tools you can use to record your screen. I’m going to use the Xbox Game Bar that comes included with Windows. We’ll need to update our video settings to not record the mouse cursor.

  1. Open the Gaming > Captures settings and turn off “Capture mouse cursor when recording a game”
  1. Open a browser, go to YouTube, and go to the video you want to record
  2. Open Xbox Game Bar and click the record button
  1. Play the video
  2. Click to stop recording when you want to stop recording.

My screen resolution is set to 1920 x 1200.

Therefore, if you open the video recording’s properties, you’ll notice that the resolution is 1920 x 1200 instead of the standard 1920 x 1080 size for 1080p resolution. We’ll need to resize this and remove the black bars.

Resize a video and remove the black bars

  1. On Windows, open ClipChamp video editor
  2. Import your video file
  3. Drag it to the preview window
  4. Make sure the aspect ratio is set to 16:9
  5. Double-click the “Fill” icon

Notice how the video content fills the preview window and gets rid of the black bars.

Export the video (usually as 1080p).

NOTE: A simpler way is to temporarily change your screen’s resolution to match that of the video, e.g. 1920 x 1080, before recording the video.

Replace Kitchen Countertop and Topmount Sink with Undermount Sink

The old sink was the top-mount kind. Water kept leaking behind the sink into the base cabinet.

The same quartz countertop was on sale from $500 to $400 (8-foot-long slab).

Found a Mexican guy in the parking lot and got him to transport and install the countertop.

The slab was leaning against the side of the truck and secured using a rope.

To remove the old countertop, I placed a towel on top of it and hit it with a sledgehammer to break it up into small pieces without pieces flying everything.

It actually didn’t take long to remove the old countertop.

I then unscrewed the old plywood and threw it away.

For an undermount sink, you need at least 19/32″ thick plywood. I had Home Depot cut a 4×8′ plywood sheet in have to make two 2×8′ sheets.

I was able to fit both 2×8′ sheets in my car 🙂

I screwed the plywood into the base drawers. There was moisture damage and a hole in the wall which I had to fix.

I patched up the hole and smoothened the wall surface.

That 19/32″ thick plywood should be strong enough for the undermount sink.

I found an 18-gauge undermount sink (30″ x 18″ x 9″ deep) at HD Supply for $175.

The installers cut a hole in the plywood for the sink. They should have used a jigsaw to make the hole.

They cut the countertop outside because it produces a lot of dust.

First, they cut the slab to length. Water was needed to keep the blade from getting too hot and keep dust from going everywhere.

Here, he’s cutting the hole for the sink using an angle grinder. I think he should have used a circular saw to make a straighter cut.

He then polished the edges while his assistant squirted water.

The sink didn’t come with a paper template for cutting a hole in the plywood and countertop. An easy way to mark an outline where to cut the whole is by turning the sink over, sticking your hand into the drain hole, and using a pencil, mark the perimeter.

I had them drill 3 holes: one for the faucet, one for a soap dispenser, and one for the dishwasher.

They put extra strong construction adhesive along the perimeter of the sink hole where the sink lip will sit. They also put it on the plywood in various places to secure the countertop to the plywood.

They then glued the backsplash to the wall and applied silicon to the joint.

When smoothening out silicone or caulk, you should always use a tool like the Husky 3-in-1 caulk tool. The triangular edge makes for a perfect finish.

When installing the p trap, I chose the flexible kind that you can cut to length. It’s much easier than fooling around with metal or PVC drain parts and it never leaks.

And this it how it came out. Not bad at all.

And here’s a close-up of the sink area.

Set-It-and-Forget-It Cheeseburger Recipe

If you’re making a burger and your meat is not frozen, then you can stick a thermometer in your patty and let the thermometer beep when the meat is at your desired temperature. The problem with this is you may have to flip the burger one or more times and, if your patty is thin or not dense, it may be difficult getting the thermometer probe in the center and staying there. If your patty is frozen, like it is at many stores that sell packages of burger patties, then you can’t stick a thermometer in it.

Frozen burger patties may not taste the best, but they are still good. Since they’re frozen, they will last long as well. To simplify the cooking process, I use the T-fal Optigrill. It grills both sides and has a drip tray to catch all fatty juices.

Here’s how to cook a frozen beef patty in the simplest way possible.

  1. Press the power button to turn on the Optigrill
  2. Press the snowflake button because your patties are frozen
  3. Press the burger button since we’re making a burger. The Optigrill will heat up as indicated by the blue light. This takes about 5 minutes.
  1. When the Optigrill beeps, it’s done heating up. Open the lid and place your patties.
  2. The Optigrill will beep and change color every time the meat reaches a doneness level.

When the Optigrill has reached your desired doneness based on the color of the doneness cycle, remove your patties. In my experience, it takes about 7 minutes to get to medium-well.

For the buns, Artesano Bakery Buns are pretty good. Don’t toast these buns. They taste good as is at room temperature.

Almond Mocha Chocolate Latte Recipe

For this recipe, I’m using the PHILIPS 3200 Series Fully Automatic Espresso Machine w/LatteGo.

Ingredients

Instructions

  1. Add almond extract and chocolate sauce to the mug (I use a pipette to transfer the almond extract).
  2. Steam milk to make 1 cup (I put mine in a measuring cup).
  3. Add 1 shot (1 oz) of espresso to your mug.
  4. Pour steamed milk into mug and mix using heat-resistant, scratch-free silicone stirrer.
  5. Enjoy

Fried Rice Made Using Automatic Pot Stirrer

One thing I really dislike when cooking is having to occasionally stir the food. This is the case with fried rice, soups, and stir-fried vegetables. Fortunately, the Koreans feel the same way. A company called LAMPCOOK with the slogan “Innovative Cooking” sells this (overpriced) automatic pot stirrer on Amazon for $155. I normally would spend that much on a pot, but like I said, I really dislike manually stirring food every so often for 10-20 minutes while cooking.

I’ve had the pot for a couple of weeks now and it actually works. But, you can’t put it over heat higher than medium. If you do, you’ll see discoloration at the center.

In this post, I’ll share my recipe for a super simple fried riced cauliflower dish. Riced cauliflower has far fewer calories than rice, and it’s a healthier option. For the flavor, I’ve found either one of the following fried rice packets to be the best.

  • Indofood Racik Bumbu Spesial Nasi Goreng
  • Bamboe Nasi Goreng

Ingredients

  • 1 lb of frozen riced cauliflower (available in packs of 5 at Costco)
  • One of the two spice packets above
  • 1/2 cup of water
  • Oil spray

Instructions

  1. Spray pot with oil
  2. Add water and riced cauliflower
  3. Remove the glass window, turn on the stirrer, and cook on medium
  4. Set a timer for 20 minutes and go do something useful
  5. After 20 minutes, the water should have evaporated. Remove the lid and stirrer arm attachment.
  6. Add the spice mix and stir with a heat-resistant and scratch-resistant silicone spatula.
  7. Optionally, mix in precooked meat, vegetables, eggs, etc.
  8. Transfer to a plate or bowl and enjoy

A Comparison of Chicken Spice Seasoning

There are many spice blends available for chicken. But, which one is the best? I tasted 7 different ones and scored each on a scale of 1 to 10. The winner goes to Target’s Good & Gather Chili Lime seasoning followed closely by Chef Merito Chicken seasoning and McCormick Perfect Pinch Rotisserie seasoning.

Spice SeasoningTaste (1-10)
Good and Gather Chili Lime7
Chef Merito Chicken6.5
McCormick Perfect Pinch Rotisserie6.5
Zatarain’s Creole Seasoning6.3
McCormick Perfect Pinch Cajun6
Old Bay Seasoning5
Lemon Pepper4.5
McCormick Grill Mates Montreal Chicken4
Tajin Clasico3
Chef Merito Chicken Marinade2
Sadaf Garam Masala0