Serpentine edge design

I have been experimenting with CSS and wondering if it's possible to create a wrapped or twisted border effect. I want to achieve a design similar to the one shown in the picture.

Answer №1

One of the simplest and cleanest solutions is to utilize svg for creating the border.

#container {
  position: relative;
  width: 200px;
  height: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="200" height="30" viewBox="-1 -2 201 33">
    <path d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>


To enhance it, you can introduce some curvature by using quadratic curves.

#container {
  position: relative;
  width: 200px;
  height: 30px;
  margin-bottom: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="200" height="30" viewBox="-1 -1 201 33">
    <path d="M0,0 h200 q-20,15 0,30 h-200 q20,-15 0,-30" stroke="black" stroke-linejoin="round" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>


Add a drop shadow effect for an extra touch.

#container {
  position: relative;
  width: 200px;
  height: 30px;
  margin-bottom: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="205" height="35" viewBox="-1 -1 205 38">
    <filter id="f">
      <feGaussianBlur stdDeviation="1.5" />
    </filter>
    <path filter="url(#f)" d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-linejoin="round" stroke-width="2" transform="translate(0,3)" fill="black" />
    <path id="shape" d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-linejoin="round" stroke-width="2" fill="white" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>


For a different approach, consider using :after and :before :pseudo-elements.

The dimensions of the :after and :before :pseudo-elements were determined through basic trigonometry.

The opposite side corresponds to the width and height of the :after and :before :pseudo-elements. One on the left has top and right borders, while one on the right has top and left borders. The left element is rotated at 45deg, while the right one is rotated at -45deg.

div {
  position: relative;
  text-transform: uppercase;
  width: 200px;
  height: 30px;
  text-align: center;
  line-height: 27px;
  border-top: 3px solid black;
  border-bottom: 3px solid black;
  box-sizing: border-box;
}
div:after,
div:before {
  position: absolute;
  content: '';
  width: 21.21px;
  height: 21.21px;
  border-top: 3px solid black;
  border-right: 3px solid black;
  transform: rotate(45deg);
  box-sizing: border-box;
  top: 1px;
  left: -9px;
}
div:after {
  border-right: 0;
  border-left: 3px solid black;
  left: 100%;
  margin-left: -10px;
  transform: rotate(-45deg);
}
<div>lorem ipsum</div>

Answer №2

Achieving this effect can be done using only CSS by manipulating the :before and :after pseudo elements.

The main benefits include the ability to leave your HTML untouched, maintaining a clear separation between content (HTML) and presentation (CSS).

body {
  text-align: center;
}
div {
  border: 2px solid;
  display: inline-block;
  position: relative;
  padding: 0 40px;
  margin: 20px;
  height: 30px;
  line-height: 30px;
  overflow: hidden;
  border-right: 0;
  border-left: 0;
}
div:after,
div:before {
  border: 2px solid;
  height: 30px;
  width: 30px;
  content: '';
  display: block;
  position: absolute;
  top: -2px;
  transform: rotate(45deg);
}
div:after {
  right: -23px;
}
div:before {
  left: -23px;
}
<div>Lorem Ipsum</div>

Answer №3

This innovative technique utilizes exclusively CSS to achieve a unique effect (implementing the approach outlined in this response but with reversed rotation of elements).

The concept involves utilizing two pseudo-elements that are rotated and positioned one below the other to create the desired shape.

This method functions as follows:

  1. There are two pseudo-elements :before and :after, each approximately half the size (considering borders) of the main .button element. The height of each pseudo-element includes 35.5px + a border of 3px on one side (top/bottom) and 1.5px on the other side (since they overlap halfway).
  2. The upper section of the shape is formed using the :before element, while the lower section is created using the :after element.
  3. A combination of rotateX with perspective is used to achieve the tilted effect, along with positioning to arrange the two elements in a way that shapes the intended design.

Note: Additional styling has been applied for a sample hover effect which transforms the shape into an elongated hexagon. While this isn't directly related to the question, it's included for illustrative purposes and some fun :). It's worth mentioning that older versions of Chrome and Safari might display incorrect results for the hover behavior, whereas the latest browser versions show the expected outcome.

/* General Button Style */

.button {
  position: relative;
  width: 300px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  text-transform: uppercase;
  color: #000;
  margin: 40px auto;
  box-sizing: border-box;
}
.button:before,
.button:after {
  width: 300px;
  left: 0px;
  height: 35.5px;
  z-index: -1;
  border: 4px solid #000;
  border-top-width: 3px;
  border-bottom-width: 3px;
}
.button:before {
  border-bottom: none;
}
.button:after {
  border-top: none;
}
.button:before {
  position: absolute;
  content: '';
  -webkit-transform: perspective(15px) rotateX(-3deg);
  -moz-transform: perspective(15px) rotateX(-3deg);
  transform: perspective(15px) rotateX(-3deg);
}
.button:after {
  position: absolute;
  top: 35.5px;
  content: '';
  -webkit-transform: perspective(15px) rotateX(3deg);
  -moz-transform: perspective(15px) rotateX(3deg);
  transform: perspective(15px) rotateX(3deg);
}
/* Hover Styles */

.button:hover:before,
.button:hover:after {
  background: #000;
}
.button:hover:before {
  top: -3px;
  -webkit-transform: perspective(15px) rotateX(3deg);
  -moz-transform: perspective(15px) rotateX(3deg);
  transform: perspective(15px) rotateX(3deg);
}
.button:hover:after {
  top: 38px;
  -webkit-transform: perspective(15px) rotateX(-3deg);
  -moz-transform: perspective(15px) rotateX(-3deg);
  transform: perspective(15px) rotateX(-3deg);
}
.button:hover {
  color: #fff;
}
<div class="button">Lorem Ipsum</div>

In case of compatibility issues with IE 8 and IE 9, the design will gracefully degrade into a square button with borders. However, due to the removal of one border (border-bottom for :before and border-top for :after), there may be a white space resembling a strike-through line in the middle. This can be addressed by incorporating specific styles for IE < 10 using conditional comments, as demonstrated in this example.

<!--[if IE]>
    <style>
        .button:after{
            top: 38px;
        }
        .button:hover:before, .button:hover:after {
            border-bottom: 4px solid black;
        }
    </style>
<![endif]-->

Screenshots showcasing the output from IE 9 and IE 8: (normal and during hover)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When a specific height threshold is surpassed, the sticky element loses its stickiness

Having trouble with implementing a sticky header? Here's a simplified version of the code: HTML: <div class="page"> <div class="header"> kkk </div> <div class="nav"> kkk </di ...

Modify the href attribute of an anchor tag that does not have a specified class or

I am currently using an event plugin that automatically links all schedule text to the main event page through anchor tags, like this: <td><a href="http://apavtcongresso.staging.wpengine.com/event/congresso-apavt-2018/">Chegada dos primeiros c ...

Utilizing JavaScript/jQuery to activate a Bootstrap navbar post-page load

Having trouble triggering Bootstrap's navbar with plain JavaScript/jQuery while using Bootstrap 3.3.6 and jQuery 1.11.3. The data structure provided for my application cannot be modified in terms of adding classes or ids. <ul> <li ...

Issue with Checkbox Input not Being Checked Upon Click (Styling with CSS Toggle Switch)

I have implemented a unique custom CSS toggle switch to customize the appearance of my checkbox inputs. Check out the project on GitHub. However, I am facing an issue where clicking on the checkbox toggles registers the click twice and does not change the ...

Add opening and closing HTML tags to enclose an already existing HTML structure

Is there a way to dynamically wrap the p tag inside a div with the class .description-wrapper using JavaScript or jQuery? This is the current html structure: <div class="coursePrerequisites"> <p> Lorem ipsum.. </p> </ ...

Creating Header Images for Websites, like the way Facebook does

Exploring how to properly configure the header image on my website has been intriguing. The main issue is that when I view it on my laptop, which has a width resolution of around 1280px, the header image's width measures about 2000px. My goal is to h ...

I'm trying to understand why this code isn't running properly. Can someone explain why my CSS is not being executed?

For some reason, using button .order{} to select elements inside the button is not applying the CSS codes as expected. The text color remains unchanged. However, when using just `.order` to select the elements, the CSS code works perfectly fine. Can someon ...

Prevent an empty carousel from showing in Laravel 9 with Bootstrap 5

In my Laravel 9 project, I have two tables in the database: Images: CREATE TABLE IF NOT EXISTS `images` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `name` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `path` varchar(191) COLLATE utf8 ...

Picture cramped within a flexbox

I have a div containing an image that is larger than the screen, and I've set the div to be full width with overflow hidden. It works perfectly without creating scrollbars. However, when I try to use flexbox on this div, the image gets squeezed. Inter ...

The hide and show buttons seem to be missing when utilizing the datatable API

For my current project, I referenced this example: https://datatables.net/extensions/responsive/examples/styling/bootstrap.html Despite trying various datatable API examples, I'm still unable to display the expand/collapse buttons. The required CSS a ...

Struggling with formatting images to ensure consistency in size using HTML and CSS

Currently, as a novice in HTML and CSS, I am encountering image misalignment issues while attempting to make them uniform in size. How can this be rectified? The existing HTML code is shown below: <div class="container text-center"> <h3> ...

Is there a way to ensure that the height of my images matches exactly with its width?

Is there a way to ensure that the height of my images always matches their width? I need the height of the images to dynamically adjust and match the width, even when the window is resized. For example, if the image width is 500px, the height should also ...

Issue regarding the carousel functioning on Bootstrap version 4.5.0

I am currently facing an issue with the carousel in the latest version of Bootstrap (4.5). I have set up a multiple item carousel by creating a grid inside it, where each item looks like this: <div class="carousel-item active"> < ...

What causes my form submission to redirect to a php file instead of staying on the

I'm currently using PHP mailer to send emails with data. The form submission is working perfectly on XAMPP locally, as I receive the email with the specified data after submitting the form. However, when I try running my app on Vercel or Netlify, it ...

Textbox textchange event triggers Javascript function when Checked=True

$('.LblQTY').on('input', function () { var currentRow = $(this).closest('tr'); var rate = parseFloat(currentRow.find('.LblRate').text()); var quantity = parseFloat($(this).val() == '' ? '0& ...

Strange occurrences observed with the interaction of multiple CSS classes

Recently, I encountered a situation with a class that had me puzzled. .lifetime .containerrow { text-align: center; height: 20px; } To enhance the appearance of certain elements by making their text bold, I attempted the following: .lifetime .co ...

Difficulty arises when attempting to remove a node using Html Agility Pack

After successfully installing the Html Agility Pack to my asp.net project, I have been able to extract data from a different web page and display it without any issues. However, I am currently facing a problem. I have identified a div with the id of header ...

Ways to determine if an object has a provided attribute?

As I work on creating a small website using django, I encountered an issue: In my site, I want to view posts in detail, but not every post includes an image attribute - leading to errors when trying to display images that do not exist. The solution lies ...

What is the best way to incorporate data from a foreach method into a function call within an HTML string?

Having trouble calling a function with data from a foreach loop while generating HTML cards and buttons from an array. The issue seems to be in the renderProducts() method. /// <reference path="coin.ts" /> /// <reference path="prod ...

Keep one row in a grid with five columns in Bootstrap

After trying out the code snippet from this Stack Overflow thread, I noticed that when I expand the screen to full size, column 5 moves to the next line on xs resizing. Is there a method to keep all columns in a single row even when the screen is resized ...