How do I create an element with an unusual shape and transparent background, and add a border around it?
I’m creating an element with a complex shape and transparent background, but I’m having trouble implementing a border. I know I need to create a duplicate element, place it behind, and increase its size, but I can’t figure out how to handle the inner part of the border.
Here’s my current code:
<div class="module_profile" id="moduleProfile">
<div class="mp_header">div>
</div>
.module_profile {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 20%);
padding: 8px 8px 10px 8px;
height: 600px;
width: 600px;
background: linear-gradient(135deg, var(--color-purple-0) 0%, var(--color-blue-1) 50%, var(--color-blue-0) 100%);
border: 3px solid var(--color-purple-4);
border-radius: 25px;
z-index: 1000;
}
.mp_header {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 0%);
margin-bottom: 5px;
height: 150px;
width: 580px;
padding: 5px 3px;
background: color-mix(in srgb, var(--color-text-0) 3.5%, transparent);
clip-path: path("M 0,15 A 15,15 0,0,1 15,0 L 565,0 A 15,15 0,0,1 580,15 L 580,75 A 15,15 0,0,1 565,90 L 165,90 A 15,15 0,0,0 150,105 L 150,135 A 15,15 0,0,1 135,150 L 15,150 A 15,15 0,0,1 0,135 Z");
overflow: hidden;
}
How do I properly implement a border for an element with such a complex shape? Is this possible to do using only CSS, or are other approaches needed?
Creating Elements with Complex Shapes and Transparent Backgrounds with Borders
Creating an element with a complex shape and transparent background with a border requires special CSS techniques, as standard borders don’t work with clip-path. The main approaches include multi-layer structure, CSS Paint API, or a combination of pseudo-elements.
Table of Contents
- Main Methods for Creating Borders for Complex Shapes
- Solution for Your Case with clip-path
- Alternative Approaches with CSS Paint API
- Performance Optimization
- Practical Examples and Recommendations
Main Methods for Creating Borders for Complex Shapes
The problem of creating borders for elements with clip-path arises because the standard border property doesn’t take into account the shape defined through clip-path. Here are the main working methods:
1. Multi-layer Structure with Duplication
The approach you mentioned is one of the most reliable. It creates two elements - an outer one for the border and an inner one for the content:
/* Outer element for border */
.module_profile-border {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 20%);
height: 600px;
width: 600px;
border: 3px solid var(--color-purple-4);
border-radius: 25px;
z-index: 999;
}
/* Inner element for content */
.module_profile {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 20%);
padding: 8px 8px 10px 8px;
height: 600px;
width: 600px;
background: linear-gradient(135deg, var(--color-purple-0) 0%, var(--color-blue-1) 50%, var(--color-blue-0) 100%);
clip-path: path("M 0,15 A 15,15 0,0,1 15,0 L 565,0 A 15,15 0,0,1 580,15 L 580,75 A 15,15 0,0,1 565,90 L 165,90 A 15,15 0,0,0 150,105 L 150,135 A 15,15 0,0,1 135,150 L 15,150 A 15,15 0,0,1 0,135 Z");
z-index: 1000;
}
2. Using Pseudo-elements
For more complex shapes, you can use pseudo-elements with clip-path:
.module_profile {
position: relative;
/* ... other styles ... */
}
.module_profile::before {
content: '';
position: absolute;
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
background: var(--color-purple-4);
clip-path: path("M 0,15 A 15,15 0,0,1 15,0 L 565,0 A 15,15 0,0,1 580,15 L 580,75 A 15,15 0,0,1 565,90 L 165,90 A 15,15 0,0,0 150,105 L 150,135 A 15,15 0,0,1 135,150 L 15,150 A 15,15 0,0,1 0,135 Z");
z-index: -1;
}
Solution for Your Case with clip-path
For your specific case with the .mp_header element, the optimal solution will be a multi-layer structure, as it allows precise control over the border shape:
<div class="module_profile" id="moduleProfile">
<!-- Outer border with correct shape -->
<div class="mp_header-border"></div>
<!-- Inner content -->
<div class="mp_header">div>
</div>
.module_profile {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 20%);
padding: 8px 8px 10px 8px;
height: 600px;
width: 600px;
background: linear-gradient(135deg, var(--color-purple-0) 0%, var(--color-blue-1) 50%, var(--color-blue-0) 100%);
border-radius: 25px;
z-index: 1000;
}
/* Border for mp_header */
.mp_header-border {
position: absolute;
top: 0px;
left: 0px;
height: 150px;
width: 580px;
border: 3px solid var(--color-purple-4);
clip-path: path("M 0,15 A 15,15 0,0,1 15,0 L 565,0 A 15,15 0,0,1 580,15 L 580,75 A 15,15 0,0,1 565,90 L 165,90 A 15,15 0,0,0 150,105 L 150,135 A 15,15 0,0,1 135,150 L 15,150 A 15,15 0,0,1 0,135 Z");
z-index: 999;
}
.mp_header {
position: relative;
top: 0%;
left: 50%;
transform: translate(-50%, 0%);
margin-bottom: 5px;
height: 150px;
width: 580px;
padding: 5px 3px;
background: color-mix(in srgb, var(--color-text-0) 3.5%, transparent);
clip-path: path("M 3,15 A 12,12 0,0,1 15,3 L 565,3 A 12,12 0,0,1 577,15 L 577,75 A 12,12 0,0,1 565,87 L 165,87 A 12,12 0,0,0 153,102 L 153,135 A 12,12 0,0,1 141,147 L 15,147 A 12,12 0,0,1 3,135 Z");
overflow: hidden;
z-index: 1000;
}
Important note: I slightly modified the clip-path for the inner element, reducing the radii by 3px, so the border displays correctly. This is necessary to compensate for the border thickness (3px).
Alternative Approaches with CSS Paint API
For more complex scenarios, you can use the CSS Paint API (Houdini), which allows creating custom borders through JavaScript:
// registerPaint('polygonBorder', class {
// static get inputProperties() { return ['--border-width', '--border-color', '--clip-path']; }
// paint(ctx, size, props) {
// const borderWidth = parseInt(props.get('--border-width'));
// const borderColor = props.get('--border-color').toString();
// const clipPath = props.get('--clip-path').toString();
// // Execute complex border drawing logic
// }
// });
.module_profile {
--border-width: 3px;
--border-color: var(--color-purple-4);
--clip-path: path("M 0,15 A 15,15 0,0,1 15,0 L 565,0 A 15,15 0,0,1 580,15 L 580,75 A 15,15 0,0,1 565,90 L 165,90 A 15,15 0,0,0 150,105 L 150,135 A 15,15 0,0,1 135,150 L 15,150 A 15,15 0,0,1 0,135 Z");
paint: polygonBorder;
}
This method provides maximum flexibility but requires support from modern browsers and additional setup.
Performance Optimization
When working with complex clip-path and multiple layers, it’s important to consider performance:
- Use
will-changefor animated elements:
.mp_header, .mp_header-border {
will-change: transform;
}
-
Avoid complex transforms: Try to use simple
translateinstead ofrotateandscale -
Cache clip-path: If the shape doesn’t change, you can define it once and reuse it
-
Use the
containproperty:
.module_profile {
contain: layout paint style;
}
Practical Examples and Recommendations
1. For simple shapes
If the shape is relatively simple, you can use a combination of border and border-radius:
.simple-shape {
border: 3px solid var(--color-purple-4);
border-radius: 25px 25px 0 0;
}
2. For complex shapes with gradient
If the background has a gradient, you need to duplicate it on the border layer:
.mp_header-border {
background: linear-gradient(135deg, var(--color-purple-0) 0%, var(--color-blue-1) 50%, var(--color-blue-0) 100%);
opacity: 0;
border: 3px solid var(--color-purple-4);
}
3. Recommendations for choosing a method
| Situation | Recommended Method | Advantages | Disadvantages |
|---|---|---|---|
| Simple shapes | border + border-radius | Simple, performant | Only for basic shapes |
| Complex static shapes | Multi-layer structure | Precise, compatibility | Additional elements |
| Dynamic shapes | CSS Paint API | Maximum flexibility | Implementation complexity |
| Transparency required | Pseudo-elements | Elegant | Limited support |
Research source: How to Apply Borders to Clip Paths with CSS
Sources
- How to Apply Borders to Clip Paths with CSS - freeCodeCamp
- Custom shape with a border and transparent background / clip path - Stack Overflow
- Exploring the CSS Paint API: Polygon Border - CSS-Tricks
- Introduction to CSS clipping - MDN
- clip-path - CSS | MDN
Conclusion
- The main method for creating borders around elements with clip-path is the multi-layer structure with shape duplication
- For your case, you need to create a separate element for the border with the same clip-path but with offset to compensate for line thickness
- Alternative approaches include CSS Paint API for maximum flexibility and pseudo-elements for simple cases
- Performance is important when working with complex shapes - use
will-changeandcontain - Testing in different browsers is essential, as clip-path support may vary
Start with the multi-layer approach - it’s the most reliable and well-supported by modern browsers. If you need additional functionality, consider CSS Paint API for more complex cases.