Building the Perfect Logo Strip
We've all been there: you're working on a website and need to display a row of logos—clients, partners, sponsors—you name it. However, logos come in all shapes and sizes, and making them look good together can be quite challenging. How do you get them to play nice and look visually appealing without spending hours tweaking each one?
This challenge becomes even trickier when you don't know in advance which logos will be in your logo row.
The Common Approach: Same Height for All
The most straightforward solution is to set all logos to the same height. Let's see how that looks.
Note: All the logos are wrapped in an additional div (.logo
). This is because we want a plain block element without intrinsic sizing, which images with width and height attributes typically have. By setting the height on the outer div and giving the image a height of 100% and width of auto, we ensure consistent sizing across all logos.
While this approach is easy to implement, it doesn't always yield a visually balanced logo strip. Wide logos might appear too big.
Adjust Heights Based on Aspect Ratio
To create a more harmonious logo strip, we can adjust the height of each logo based on its aspect ratio. If a logo is significantly wider than it is tall (aspect ratio greater than one), we'll reduce its height accordingly. The wider the logo, the smaller its allowed height. This way, all logos maintain a visual balance.
To achieve this, we need to know the original width and height of each logo. This shouldn't be a problem when working with a CMS, as you can usually access the image dimensions easily. And if you're creating the images yourself, it's even easier.
Setting Up the HTML:
On each of the .logo
divs, we'll set two custom properties: --width
and --height
. Be sure to use unitless values here because in CSS calculations, you cannot remove a unit once it's there. 🙂
html<div class="logo-row">
<div class="logo" style="--width:49; --height: 48;">
<img src="first-logo.svg" alt="" />
</div>
<div class="logo" style="--width:228; --height: 48;">
<img src="second-logo.svg" alt="" />
</div>
...more logos...
</div>
The CSS Magic:
css.logo-row {
--base-height: 3rem;
--scale-factor-horizontal: 0.1;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 3rem 2rem;
}
.logo {
--base-ratio: calc(var(--width) / var(--height));
aspect-ratio: var(--base-ratio);
--factor-horizontal: min(
var(--scale-factor-horizontal) * -1 * var(--base-ratio) + var(--scale-factor-horizontal) + 1,
1
);
height: max(
var(--base-height) / 2,
var(--base-height) * var(--factor-horizontal)
);
& img {
width: 100%;
height: auto;
}
}
There is a lot going on here. Let's break it down step by step.
1. Setting Base Variables
We set --base-height
and --scale-factor-horizontal
on the .logo-row
. These variables will be used in our calculations for each logo.
css.logo-row {
--base-height: 3rem;
--scale-factor-horizontal: 0.1;
/* ... */
}
2. Calculating Aspect Ratio
For each .logo
, we calculate its aspect ratio and store it in --base-ratio
.
css.logo {
--base-ratio: calc(var(--width) / var(--height));
aspect-ratio: var(--base-ratio);
/* ... */
}
3. Calculating the Scaling Factor
Now comes the juicy part! We need to calculate a scaling factor that adjusts the height of each logo based on its aspect ratio. This ensures that wider logos are scaled down proportionally, maintaining visual harmony across the logo strip.
The Formula
We use linear interpolation to compute the scaling factor, which returns 1
when the aspect ratio is 1
. Here's the formula:
css--factor-horizontal: min(
(-1 * var(--scale-factor-horizontal) * var(--base-ratio)) +
var(--scale-factor-horizontal) + 1,
1
);
Since we know the value of the --scale-factor-horizontal
variable, we can insert it here to simplify:
css--factor-horizontal: min(
(-0.1 * var(--base-ratio)) + 1.1,
1
);
Let's Plug in Some Numbers
- Aspect Ratio of 1: (-0.1 * 1) + 1.1 = 1
- Aspect Ratio of 2: (-0.1 * 2) + 1.1 = 0.9
- Aspect Ratio of 3: (-0.1 * 3) + 1.1 = 0.8
This means a logo with an aspect ratio of 2:1 will have 90% the height of a logo with a 1:1 aspect ratio.
4. Adjusting the Height
We set the height of each logo by multiplying the base height by the calculated scaling factor. To ensure that even the widest logos don't become too small, we also use a max
function to prevent the height from dropping below half of the base height.
cssheight: max(
var(--base-height) / 2,
var(--base-height) * var(--factor-horizontal)
);
Adding Adjustments for Portrait Logos
So far, we've been dealing with logos that are square or wider—that is, logos with an aspect ratio of 1 or greater. But occasionally, you might need to include a portrait-oriented logo that's taller than it is wide, with an aspect ratio less than 1.
The challenge with portrait logos is that their aspect ratios are between 0 and 1 while landscape logos have a ratio that is between 1 and infinity. Therefore the interpolation method we used for wider logos doesn't make a noticeable difference here, and scaling them using the same factor doesn't adjust their size enough.
To solve this, we'll introduce a new resize factor specifically for portrait logos, called --factor-vertical
.
For the final height-calculation, instead of using a max function to prevent logos from becoming too small, we'll switch to a clamp function. This lets us set both minimum and maximum height limits, ensuring that portrait logos don't become too big and overshadow the rest.
Here's the final version of our logo adjustment technique. You can experiment with the two scaling values and adjust the base height of the logos to see how it affects the overall appearance of the logo strip. If you have ideas on how to further refine this solution or insights you'd like to share, I'd love to hear from you! Feel free to reach out and share your suggestions.
UPDATE Sept. 25: Scaling Logos to Equal Area
I want to give a big shoutout to Roman for suggesting an alternative solution to our logo sizing challenge. His method aims to scale all logos so that they occupy the same area as a square logo would. In other words, the product of the width and height (the area) of each logo becomes consistent across all logos.
How it Works
- Calculating the Square's Area: First, we take the base height and multiply it by itself to get the area of a square logo with that height.
- Finding the Scale Factor: Next, we determine the scale factor by dividing the square's area by the area of each logo (its width multiplied by its height). Since we're scaling both dimensions uniformly, we take the square root of that ratio.
- Scaling the Logo: We then multiply the height of each logo by this scale factor. This adjusts the logo's size so that it occupies the same area as the square logo.
The beauty of this approach is that it works seamlessly for both portrait and landscape logos, ensuring a consistent visual presence across the logo strip.
Adjusting the Visual Impact
While Roman's solution is mathematically sound, I found that making all logos occupy exactly the same area can sometimes lead to visual inconsistencies, especially when logos have extreme aspect ratios. To address this, I introduced a strength variable that allows us to control how strongly the scaling is applied.
- Calculating the Scaled Height: First, we compute the scaled height using the scale factor from Roman's method.
- Applying the Strength Factor: Then, we interpolate between the base height and the scaled height using the strength variable. When the strength is set to
1
, we get the full effect of the scaling. When it's set to0
, all logos use the base height without any scaling. Values in between allow for fine-tuning the visual balance to suit your specific needs.
A Caveat: Dealing with Units in CSS Calculations
One challenge with this method is that to calculate the scale factor accurately, we need unitless values. However, CSS variables often carry units, which can complicate calculations that require pure numbers.
To overcome this, we need to convert the base height into a unitless pixel value. This can be achieved using a clever CSS trick involving trigonometric functions, specifically atan2
and tan
. By using these functions, we can isolate the numerical value from the unit, allowing us to perform the necessary calculations without units interfering.
If you want to learn more about this, you can have a look at my blog post "Speed vs. Duration – A Use Case for Mixed Unit Division" where I delve into this topic in more detail.
Logos Used in This Post
In case you're curious about the logos featured in our examples, here's where they come from:
- 9elements Logo – 9elements.com
- img.ly Logo – img.ly
- CSS Café Meetup Logo – css.cafe
- Das Ruhrgebiet Magazin Logo – dasruhrgebiet.de
- 9elements Suggestion for CSS 4/5 Logo - new CSS logo discussion
- Beloved CSS Owl Selector Logo
- 10xD Logo – 10xd.de
By the way, if you’re on the hunt for a shiny new logo, all of these were crafted by the talented team at 9elements. Just saying! 😉