Add custom image shapes

The borders and image shapes are generated using SVG clip paths. When combined with CSS, it will crop the image inside of the SVG path shape. Here are some good articles about this technique in general:

The techniques we use in the theme are ones that we cross browser tested to display properly based on Shopify's browser support requirements for themes that are for sale in their theme store as of November 2022 when this theme originally debuted. We also chose to support Safari 13 and earlier as we had customers reach out to us for support for this browser. There may be other techniques that are mentioned in the linked articles that will work that we didn't choose to utilize because of previous issues with browser support. If you decide to try them and have success, let us know!

Adding a custom image shape

1. Create the shape

Shapes with all sharp edges

If your shape does not have any rounded edges and only has sharp points, you can create the clip path in pure CSS using a polygon value. For example, here is the hexagon shape used when the Theme style is set to "Sharp" in the Whisk theme:

.theme-style--sharp .element--hexagon {

-webkit-clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);

clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);

}

We include the "-webkit-clip-path" vendor prefixed version to support Safari versions 13 and older, and Samsung browsers. The vendor prefixed version should always be written above the regular version, so that the regular version can override it when supported.

There are several online clip path generators out there, but this is our favorite one. You can start with a pre-built shape and edit it in the browser and grab the code to use.

https://10015.io/tools/css-clip-path-generator

For this tutorial, we'll add this heptagon shape.

Copy the CSS Code from the bottom of the page. We'll add it to the file in the Assets folder in our theme titled "styles-utilities-element-object.css".

If you want this shape to be the same for both theme styles (soft or sharp), you can add it with one class name to this file. We recommend adding it nearby the other shapes in this file under the commented title "/* Shapes */" , to keep things organized. The class name should start with "element—" followed by the name of the shape. You can choose whatever name you like, just make sure it isn't already taken. Note that the vendor prefixed version with "-webkit" prepended to the property name has the exact same value as the regular version copied from the generator.

.element--heptagon {

-webkit-clip-path: polygon(50% 0%, 90% 20%, 100% 60%, 75% 100%, 25% 100%, 0% 60%, 10% 20%);

clip-path: polygon(50% 0%, 90% 20%, 100% 60%, 75% 100%, 25% 100%, 0% 60%, 10% 20%);

}

Shapes with curves

If your shape has curved edges, then instead of using the polygon clip path we need to use a url clip path and add those coordinates in another file in the Whisk theme, "Snippets/svg-clip-paths.liquid". Here is how you can do that.

Make sure that your SVG shape is one path. The path coordinates are the contents the d="" attribute on the path element. Here's an example of an SVG we created in Adobe Illustrator that we are using in the theme that is a hexagon with rounded edges. We use this hexagon in the "soft" theme style.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 92.16 82">

<path d="m65.04,0H27.12c-2.92,0-5.61,1.56-7.07,4.08L1.09,36.92c-1.46,2.53-1.46,5.64,0,8.16l18.96,32.84c1.46,2.53,4.15,4.08,7.07,4.08h37.92c2.92,0,5.61-1.56,7.07-4.08l18.96-32.84c1.46-2.53,1.46-5.64,0-8.16L72.11,4.08c-1.46-2.53-4.15-4.08-7.07-4.08Z" />

</svg>

If you don't have an vector editing program like Adobe Illustrator that can edit and create SVGs, here's a link to a website where you can draw your own and grab the path coordinates: https://yqnn.github.io/svg-path-editor/

There's one important extra step to this technique — in order to use a path in CSS as a clip-path, we have to convert the path coordinates to a relative path within a viewbox of 0 0 1 1. Fortunately, there is a life saving website that converts SVG paths to CSS clip path ready coordinates so we don't have to do any math! 😅 https://yoksel.github.io/relative-clip-path/

Using the above example, we'll paste the value from the d="" attribute into the first input field, "Insert clip-path coordinates for userSpaceOnUse" and the website will generate the updated path for us with a preview. Copy the coordinates that are generated in the second input titled "Take clip-path coordinates for objectBoundingBox".

We'll take these coordinates, and add them to the file "Snippets/svg-clip-paths.liquid". Create a new clipPath element inside of the <defs> element inside of the <svg>. Here's what our clipPath element for the hexagon with rounded edges looks like:

<clipPath id="rounded-hexagon" clipPathUnits="objectBoundingBox">

<path d="m0.706,0 H0.294 c-0.032,0,-0.061,0.019,-0.077,0.05 L0.012,0.45 c-0.016,0.031,-0.016,0.069,0,0.1 l0.206,0.4 c0.016,0.031,0.045,0.05,0.077,0.05 h0.411 c0.032,0,0.061,-0.019,0.077,-0.05 l0.206,-0.4 c0.016,-0.031,0.016,-0.069,0,-0.1 L0.782,0.05 c-0.016,-0.031,-0.045,-0.05,-0.077,-0.05">

</clipPath>

The "id" will be the name of the SVG when it is referenced in the CSS, so it needs to be something unique that isn't used anywhere else. The clipPath also needs to have the attribute and value...

clipPathUnits="objectBoundingBox"

...in order to render properly.

Now we can add our unique element class to the "Assets/styles-utilities-element-object.css" file but instead of adding a polygon value, we'll add a url value with the id of the clipPath we just created. We include the "-webkit-clip-path" vendor prefixed version to support Safari versions 13 and older, and Samsung browsers. The vendor prefixed version should always be written above the regular version, so that the regular version can override it when supported. The class name should always start with "element—".

.theme-style--soft .element--hexagon {

-webkit-clip-path: url(#rounded-hexagon);

clip-path: url(#rounded-hexagon);

}

In the above example, we only want the rounded hexagon to show on the "Soft" theme style of the theme. this is what the CSS would look like if we want it to be for both the "Soft" and "Sharp" theme styles.

.element--hexagon {

-webkit-clip-path: url(#rounded-hexagon);

clip-path: url(#rounded-hexagon);

}

2. Give the new shape an aspect ratio

The next thing you need to do in this file is add an aspect ratio and an optional padding hack fallback to give the element it's size. The image will fill the width of it's container, and adding the aspect ratio sets it's height so that the shape will always be the same everywhere you use it.

The padding hack fallback is specifically for Safari version 14 and older, but it will also help with other older browsers. You can skip it if you do not need to support older browsers.

Here is an article that explains the padding hack. In summary, before there was an aspect ratio CSS property, this padding hack was used to create an aspect ratio: https://css-tricks.com/aspect-ratio-boxes/

We want to add the padding hack CSS code first in the file so that we can override it later with the aspect-ratio CSS for browsers that support it.

In our example, we want the heptagon to be a square, so we want the padding-top value to be 100%. This is the most common aspect ratio for the shapes in the Whisk theme, so we can add our element class to the bottom of the class list declaration that already exists. Make sure to add a comma after the class name before it, which in the below example is "element—hexagon-rotated".

.element--square,

.element--circle,

.element--arch,

.element--half-arch-left,

.element--half-arch-right,

.element--diamond,

.element--hexagon-rotated,

.element--heptagon {

padding-top: 100%;

}

Next, we can add the aspect-ratio declaration for our new shape. Let's scroll down the "styles-utilities-element-object.css" file until you find the opening line for the feature query for aspect ratio. It looks like this:

@supports (aspect-ratio: 1) {

...CSS aspect-ratio declarations

}

Inside this declaration, you can add the aspect-ratio for your element. Since we want a square with even height and width, our aspect-ratio is "1". We can add our element to the current class list for that declaration similar to what we have done above for the padding hack.

@supports (aspect-ratio: 1) {

.element--square,

.element--circle,

.element--arch,

.element--half-arch-left,

.element--half-arch-right,

.element--diamond,

.element--hexagon-rotated,

.element--heptagon {

aspect-ratio: 1;

}


...more CSS aspect-ratio declarations

}

3. Use the shape in the theme

To use the shape in the theme, you need to add the shape name as an option in the schema portion in section files that offer an image shape option. The following example is from the "Image with text" section. Below we've added the "Heptagon" as the first option.

You'll want to add the shape as a new "value" with a "label". "Value" is the shape name from the CSS class name, everything after the double dashes (capitalization matters, so we like to keep things all lowercase to make it simple), and "label" is what the shape name will look like in the dropdown selector in the theme editor. The labels that are currently in the file are all locale translations, but if you aren't familiar with locales, you can just give your shape a name straight in this file.


{

"type": "select",

"id": "shape",

"options": [

{

"value": "heptagon",

"label": "Heptagon"

},

{

"value": "square",

"label": "t:image_shape.option_square"

},

{

"value": "landscape",

"label": "t:image_shape.option_landscape"

},

{

"value": "portrait",

"label": "t:image_shape.option_portrait"

},

{

"value": "hexagon",

"label": "t:image_shape.option_hexagon"

},

{

"value": "circle",

"label": "t:image_shape.option_circle"

},

{

"value": "arch",

"label": "t:image_shape.option_arch"

},

{

"value": "triangle-up",

"label": "t:image_shape.option_triangle_up"

},

{

"value": "triangle-down",

"label": "t:image_shape.option_triangle_down"

},

{

"value": "diamond",

"label": "t:image_shape.option_diamond"

},

{

"value": "flower",

"label": "t:image_shape.option_flower"

}

],

"default": "square",

"label": "t:image_shape.label"

},

You can learn more about Shopify's schema architecture in their Section schema documentation.

Still need help? Contact Us Contact Us