Aayush Dahal
Aayush Dahal

Reputation: 1182

Need to have half width border in one side and full width border in another side

Here is my html and css code:

.image-box{
  max-width: 300px;
  position: relative;
}
.image-box img{
  max-width: 100%;
  width: 100%;
  object-fit: cover;
  
   border: 8px solid #000000;
    border-right: 0;
    border-bottom: 0;
    /* border-image: linear-gradient(to right, #000 68%, transparent 32%) 100% 1; */
}
<div class="image-box">
   <figure>
     <img src="https://via.placeholder.com/300"  alt="">
  </figure>
</div>

While running this, I receive this.

enter image description here

But, I want to have something like this:

enter image description here

If I uncomment this line

border-image: linear-gradient(to right, #000 68%, transparent 32%) 100% 1; 

enter image description here

Then it shows half width border on top, but this also make the left border disappear and show like this.

Upvotes: 1

Views: 356

Answers (3)

Oskar Grosser
Oskar Grosser

Reputation: 3434

Disclaimer: Not an exhaustive list. Try to come up with yet another solution!

With background-image: linear-gradient()

To make a linear-gradient look like a border, we can add padding to the image and a hard color-stop to the gradient:

.image-box {
  --thickness: 8px;
}
.image-box img {
  padding-top: var(--thickness);
  padding-left: var(--thickness);
  background-image: linear-gradient(to right, black 60%, white 60%);
}

figure{margin:0;line-height:0}
<div class="image-box">
  <figure>
    <img src="https://via.placeholder.com/300">
  </figure>
</div>

A potential problem with this is that only one side of the border may be shorter.

With Pseudo-elements

Pseudo-elements can be used for presentational styling. You can easily identify them in your CSS by their double-colons (e.g. ::before, ::marker).

Sidenote: While still supported for legacy reasons, they can also be written with a single-colon (e.g. :before). Do yourself a favour and use the double-colons.

We can use pseudo-elements to create the border.

I will use custom properties to make the code easier to change.
Personally, I enjoy the method Placing behind the most, because that way no bleeding through of the parent's background should happen in extreme (zoom) cases.

Composition

Composite the border with ::before for the left and ::after for the top side. Since these are separate elements, we can define their width and height individually:

.image-box::before, .image-box::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  background-color: black;
}
.image-box::before { /* Left */
  width: var(--thickness);
  height: 100%;
}
.image-box::after { /* Top */
  width: 60%;
  height: var(--thickness);
}

.image-box {
  --thickness: 8px;
  position: relative;
  /* Leave space for border */
  padding-top: var(--thickness);
  padding-left: var(--thickness);
  max-width: 300px;
  box-sizing: border-box;
}
.image-box img {max-width:100%}

figure{margin:0;line-height:0}
<div class="image-box">
  <figure>
    <img src="https://via.placeholder.com/300">
  </figure>
</div>

Placing behind

Place the image on top of a pseudo-element to make it look like a (partially wide) border:

.image-box::before, .image-box>figure {
  grid-area: 1/1 / 1/1; /* Place both on first grid-cell */
}
.image-box::before {
  content: "";
  width: 60%;
  height: 100%;
  background-color: black;
}

.image-box {
  --thickness: 8px;
  max-width: 300px;
  display: grid;
}
.image-box img {
  /* Leave space for border */
  padding-top: var(--thickness);
  padding-left: var(--thickness);
  width: 100%;
  box-sizing: border-box;
}

figure{margin:0;line-height:0}
<div class="image-box">
  <figure>
    <img src="https://via.placeholder.com/300">
  </figure>
</div>

Using clip-path: polygon()

Specify each point of the "top-left corner" shape in polygon():

.image-box {
  position: relative;
  padding-top: 8px;
  padding-left: 8px;
  max-width:300px;
}
.image-box::before {
  --thickness: 8px;
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 60%;
  height: 100%;
  clip-path: polygon(
    0 0,
    100% 0,
    100% var(--thickness),
    var(--thickness) var(--thickness),
    var(--thickness) 100%,
    0 100%);
  background-color: black;
}

figure {margin:0;line-height:0}
<div class="image-box">
 <figure>
   <img src="https://via.placeholder.com/300">
 </figure>
</div>

Why not use border?

Edit: Apparently border-image is a thing. See an example. Bottom section is therefore outdated.

Unfortunately, each side of a border can only be a single color. This means the black & white top border is not possible by only using the border property.

A solution to this would be to redraw over part of the border that we don't want:

#example {
  padding: 1rem;
  background-color: slateblue;
}

.image-box {
  --thickness: 8px;
  position: relative;
  border: 0 solid black;
  border-top-width: var(--thickness);
  border-left-width: var(--thickness);
  max-width: 300px;
}
.image-box::after {
  content: "";
  position: absolute;
  top: calc(-1 * var(--thickness));
  right: 0;
  /* 100% - <length> + <thickness left-side> */
  width: calc(100% - 60% + var(--thickness));
  height: var(--thickness);
  background-color: white;
}

body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
figure{margin:0;line-height:0}
<div class="image-box">
  <figure>
    <img src="https://via.placeholder.com/300">
  </figure>
</div>

<div id="example">
  <div class="image-box">
    <figure>
      <img src="https://via.placeholder.com/300">
    </figure>
  </div>
</div>

But as you can see, this way we will lose the background of the parent. Hard-coding some color only works if the parent's background is a solid color. If the parent's background is an image, this won't work.

Also, having to tell .image-box the color to draw over with is redundant information (because the background already exists) and would only cause more mental overhead for the developer.

Upvotes: 3

Temani Afif
Temani Afif

Reputation: 272909

you are almost good with border-image. You need to correctly define the slice.

.image-box {
  max-width: 300px;
  position: relative;
}

.image-box img {
  max-width: 100%;
  width: 100%;
  object-fit: cover;
  border: 8px solid #000000;
  border-right: 0;
  border-bottom: 0;
  border-image: linear-gradient(to right, #000 68%, transparent 32%) 1;
}
<div class="image-box">
  <figure>
    <img src="https://via.placeholder.com/300" alt="">
  </figure>
</div>

Upvotes: 1

Zen
Zen

Reputation: 156

You can do something like this using pseudo classes to make the border at the top like how you want it to be achieved:

What it does is hide the half of the border at the top.

.box {
  width: 150px;
  height: 150px;
  background-color: black;
  border-top: 5px solid red;
  border-left: 5px solid red;
  position: relative;
}

.box:after {
  content: "";
  width: 50%;
  height: 5px;
  background-color: white;
  position: absolute;
  right: 0;
  top: -5px;
}
<div class="box"></div>

Upvotes: 4

Related Questions