Logo
Jaime Elso

AWS Solutions Architect

ES

MyWebsite

I have been making websites all my life, but never one for myself. Well here is MyWebsite a professional place to share my own projects with the world. As you can see, It's not the most complicated or craziest design, but it's minimalistic, simple and clean. The main attribute I wanted to preserve in my web is its speed. This is why I don't use external frameworks or platforms as wordpress: just HTML, CSS and JavaScript. In this post I will share with you the keys of my design and how it works.

Website structure

The most important practice when creating a project is to properly structure the folder and all your documents according to good practices. To assist others, I have created a website structure template that can be downloaded and used to start building your site.

HTML

In order to please Sr.Google, all the meta tags have been written carefully with titles and descriptions trying to get the best SEO score possible for my personal brand and my projects. To give the user a full visual experience, it is critical to have all the possible favicons, banners for social media sharing or google chrome theme color on mobiles. The body is divided into three large blocks using the descriptor tags incorporated in HTML5.

<body>
    <header> ... </header>
    <main>   ... </main>
    <footer> ... </footer>
</body>

CSS

a.css is the main stylesheet for the entire website and should always load first for proper viewing. For specific elements or styles that are only required on certain pages, there are other .css files such as the contact form or the mobile menu hamburguer. The technique that I always use when starting a new general css is to set these styles.

* {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
}				

Some people call it "CSS Reset" because it deletes all differences across browsers and you will never again encounter strange things that you did not expect. For a large website, this could be a problem as it is too heavy on the rendering agent to apply rules to every single element in the document. However, for a website like mine, it works fine.

JS

a.js is the website engine; it controls all dynamic elements such as colors, click events, copy to clipboard, and manages all the CSS for correct web representation. A pattern that I usually follow in my JS object is to make a play on words with the variable name and the start function, for example, this one using my last name (Elso).

const el = {
    events: () => { ... },
    load: () => { ... },
    so: () => {
        el.load();
        el.events();
    }
};
el.so();		

Another good practice is to place the object functions in an upward order, so a function will always call functions that are higher. The load function controls all the elements in the first moment that the page is loaded, and the events function controls everything that needs to change at specific moments.

Design

Why a light interface? For me, a light interface represents cleanliness, and it's still the default look of the site. Why color swapping? The most used highlight color in my previous designs was blue. It's time to innovate, and with no other preferred color, why not use all of them? The idea is to capture the user's visual attention since there are no colorful images.

Distribution and spaces

Distancias

This is something I learned from my mentor Fernan García de Zúñiga: "all numbers have to be multiples of eight", and I always keep this in mind while programming an interface. The 8 point grid system respects the variety of screen sizes and pixel densities for all devices. So, height or width, margin or padding will be an increment of 8, which will give the user a consistent aesthetic feel.

Colors swapping

If you've noticed, when you load a page, the accent color used across the site starts as a different one each time and then cycles through the rest via animated @keyframes. The original implementation shuffled an 8-color array with the Fisher-Yates algorithm on every load and injected a fresh <style> block with the computed keyframes — I had to redesign it when I tightened the site's Content-Security-Policy to drop 'unsafe-inline' from style-src, since that blocks both a style="" attribute and any <style> element generated by JavaScript at runtime.

The fix keeps the same visual effect with a fully static CSS: 8 pre-computed "palette" classes, each one just reassigning the same 8 custom properties (--c0 through --c7) that the @keyframes already reference, so the animation itself never changes — only which color plays at which step. On load, the site picks one of the 8 rotations at random and adds the matching class to <html>; nothing is generated, only a class is toggled, which the CSP allows.

.palette-1 { --c0:#086D72; --c1:#197209; --c2:#6B6407; --c3:#8E550C; --c4:#C50D0D; --c5:#BF0D5E; --c6:#A80DBA; --c7:#0D61B9; }
/* ...palette-2 through palette-7, each one rotation of the same 8 colors */

@keyframes color-animation {
    0%    { color: var(--c0); }
    12.5% { color: var(--c1); }
    /* ...through 100% { color: var(--c0); } */
}
load: () => {
    const n = Math.floor(Math.random() * 8);
    if (n > 0) {
        document.documentElement.classList.add(`palette-${n}`);
    }
}

Font

Roboto is a sans-serif Google font and is perhaps the closest approach to Helvetica. "Modern, yet approachable" is how they describe it, and it's true, it's a clean typeface with a straightforward, geometric design that offers clean lines, rounded and somewhat emotional. For the code module, the typeface I use is another from the family, Roboto Mono. Monospaced typography has always been used in programming languages (text editors and terminals), so this typography immediately brings to mind the idea that you are reading source code.

Dark mode

The light interface described above is still the default, but it's no longer the only option: the site now follows the visitor's system preference (prefers-color-scheme) and offers a manual sun/moon toggle in the header, persisted in localStorage. Almost every color in a.css is already a custom property (--color-black/--color-white/--color-bg act as "ink" and "paper"), so most of the dark theme is just swapping those tokens inside a media query and a [data-theme="dark"] block — a handful of surfaces that are deliberately dark in both themes (the mobile menu, the footer) keep literal colors instead, by design.

The one tricky part is avoiding a flash of the wrong theme on load: the toggle's choice has to apply before the first paint, but it can't be inline (the CSP again). The fix is a tiny external script, theme-init.js, loaded blocking as the very first thing in <head>, before any stylesheet, which reads the saved preference from localStorage and sets [data-theme] on <html> immediately.

Contact form

Currently, MyWebsite is hosted on Cloudflare's Pages service, which allows for easy creation and publishing of websites. However, this service does not allow for backend code execution, so only static websites can be published. The form itself can be created with HTML and CSS, but to implement a message processing logic I need to execute code on the backend. Instead of moving the website to a different host, I will take advantage of the tools provided by AWS to implement a serverless backend that handles this logic.

Check out the full post where I detail how I implemented the contact form using a serverless backend on AWS.

Page quality

Performance

Lighthouse is an open-source, automated tool for improving the quality of web pages. If you generate a report on my website, you will get that result. Nice! Sr.Google is happy with me.

Performance

You must include a preconnect in the head section for external resources that I am going to work with, for example, third-party usage like Google Analytics. I must also preload my page fonts.

<link rel="preconnect" href="https://www.google-analytics.com">
<link rel="preload" href="/font/RobotoMono-Regular.woff2" as="font" crossorigin="anonymous">

It's important to have properly sized images, which I can achieve using online compression tools or other programs that don't decrease the quality of the photo to the human eye. Minifying the CSS and JS files, enabling Gzip compressor on your resource requests, using HTTP/2, and developing an efficient cache policy will improve web performance.

This website implements lazy loading, a technique that improves the performance of a website by delaying the loading of images until they are needed. When a user visits the webpage, only the images that are visible on the screen are loaded. The rest of the images are left unloaded until the user scrolls down the page. This can significantly reduce the amount of data that needs to be transferred, making the webpage load faster, especially on mobile devices or when the internet connection is slow.

<img src="/img/MyWebsite/distancias.png" width="1248" height="571" alt="Distancias" loading="lazy">

I used to hand-roll this with the Intersection Observer API — watch for each image entering the viewport, then swap a data-src attribute into src. Browsers caught up: the native [loading="lazy"] attribute now does exactly that, with no JavaScript and no risk of a broken image if a script fails to load. Every image gets it except the first, above-the-fold one on each page, which should load immediately instead of waiting to be observed.

Accessibility

Background and foreground colors have a sufficient contrast ratio (at least 4.5:1), which you can check using the inspect tool or websites. The html element has "en" as its [lang] attribute, [id] attributes on the page are unique, all the pages have a "title" element less than 70 characters, and all the image elements have [alt] attributes.

Responsive

Responsive design is a way to put together a website so that it automatically scales its content and elements to match the screen size on which it is viewed. There are different ways to achieve this, such as using media queries in CSS, which can be useful but require a lot of code for different screen sizes. A better practice is using resizable containers with a non-fixed size. There are only two significant changes between mobile and desktop: how the header elements are displayed, and hiding the copyright message in the footer when the screen width is less than 800px. This is an example of a div container that I always use to set a maximum width (for the largest screens) and a calculated width when the screen size is less than the maximum.

div.container {
    max-width: 1248px;
    padding: 0 16px;
    width: calc(100% - 32px);
    margin: 0 auto;
}				

Best Practices

Use HTTPS instead of HTTP, use HTTP/2 for your own resources, make sure that links to cross-origin destinations are safe (using rel="noopener"), include the HTML doctype, ensure that there are no browser errors logged to the console, and display images with the correct aspect ratio.

SEO

The document has a valid rel=canonical and this is important because you have to set the canonical to the page URL on all pages. If you don't, you will leave the SEO score of this page to another page that you set. If the page content exists in other languages, you must indicate this in the hreflang, and you should also include the page itself with its language.

<link href="https://jaimeelso.com/post/mywebsite" rel="canonical" />
<link rel="alternate" hreflang="en" href="https://jaimeelso.com/post/mywebsite" />

In the robots.txt you specifies how you want your website to be crawled or indexed by the crawlers, and also indicate where de sitemap.xml file is.

Progressive Web App

PWAs (Progressive Web Apps) are an easy way to transform your website into desktop, Android, or iOS applications. The site already ships a manifest.json with icons and metadata, so it's installable. What it deliberately doesn't have is a service-worker.js: offline support and caching logic are real complexity for a static site with no interactive features to preserve offline, so I evaluated it and decided against it — I'd rather add that complexity when there's a concrete reason for it than build it speculatively.

Thanks for reading! Catch you in the next one.