95

I'd like to have a div that looks like this:

border example

Is this possible to do with HTML + CSS? I will also be animating this div with jQuery. When the div is hidden I would like the title and the top line to show.

12 Answers 12

147

Yes, but it's not a div, it's a fieldset

fieldset {
    border: 1px solid #000;
}
<fieldset>
  <legend>AAA</legend>
</fieldset>

Sign up to request clarification or add additional context in comments.

6 Comments

You can make a workaround... Also, you should have commented that and not post it as an answer
I don't see why it is a workaround, to me it is a solution. What functional difference does it make whether it's a div or a fieldset?
@Bazzz- it's wrong semantics. "The fieldset element represents a set of form controls optionally grouped under a common name." - HTML5 spec. Where are the controls? What we actually need is a display:fieldset CSS setting. Sadly there isn't one.
@Alohci Agree! Though, I don't think the OP said there won't be any form controls in the fieldset. It could still be that he wants to put form controls inside :)
kudos for this, ten years later and I hadnt even heard of fieldsets until now. great answer
|
62

You can do something like this, where you set a negative margin on the h1 (or whatever header you are using)

div{
    height:100px;
    width:100px;
    border:2px solid black;
}

h1{
    width:30px;
    margin-top:-10px;
    margin-left:5px;
    background:white;
}

Note: you need to set a background as well as a width on the h1

Example: http://jsfiddle.net/ZgEMM/


EDIT

To make it work with hiding the div, you could use some jQuery like this

$('a').click(function(){
    var a = $('h1').detach();
    $('div').hide();
    $(a).prependTo('body');    
});

(You will need to modify...)

Example #2: http://jsfiddle.net/ZgEMM/4/

5 Comments

I dont like this answer it has many constraints: the top margin is related to the font size of the h1, what if the font size changes later, you'd need to update all the margins. background: white prevents any background image from being visible throught the h1, it feels a little inflexible. I just have a feeling that using this approach is like opening up for more styling issues later. just my thought.
I like this. Is there a way to hide the side and bottom border when the div inside is hidden? jsfiddle.net/ZgEMM/3
What I was asking was how to keep the top border and hide the other three, but I decided not to do that. This is what I ended up going with: jsfiddle.net/ZgEMM/10
You will have problems if someone tries to print this page as browsers typically omit backgrounds by default.
Today I discussed this problem with a colleague. To prevent the issue from defining a fixed width (titles vary in length), we just used floating. So instead of width: XXpx; we use float: left;.
20

I know a bit late to the party, however I feel the answers could do with some more investigation/input. I have managed to create the situation without using the fieldset tag - that is wrong anyway as if I'm not in a form then that isn't really what I should be doing.

/* Styles go here */

#info-block section {
    border: 2px solid black;
}

.file-marker > div {
    padding: 0 3px;
    height: 100px;
    margin-top: -0.8em;
    
}
.box-title {
    background: white none repeat scroll 0 0;
    display: inline-block;
    padding: 0 2px;
    margin-left: 8em;
}
<aside id="info-block">
  <section class="file-marker">
    <div>
      <div class="box-title">
        Audit Trail
      </div>
      <div class="box-contents">
        <div id="audit-trail">
        </div>
      </div>
    </div>
  </section>
</aside>

This can be viewed in this plunk:

Outline box with title

What this achieves is the following:

  • no use of fieldsets.

  • minimal use of CSS to create effect with just some paddings.

  • Use of "em" margin top to create font relative title.

  • use of display inline-block to achieve natural width around the text.

Anyway I hope that helps future stylers, you never know.

7 Comments

Despite being a little more complex than I'd like, I really like this answer because it isn't another CSS hack or bad practice. +1
Your Plunker link does not load.
@HoldOffHunger seems to be working fine here, what browser did you try?
Firefox, loads up and works perfect in Chrome. I was hoping an html/css demo wouldn't require much more, but Chrome is pretty standard sure. Glad to see an answer with an aside/section tag.
@HoldOffHunger I may a slight improvement which may help Firefox, however I see that plunkr is going through some Alpha phases right now so it may not be 100%.
|
12

Text in Border with transparent text background

.box{
    background-image: url("https://i.sstatic.net/N39wV.jpg");
    width: 350px;
    padding: 10px;
}

/*begin first box*/
.first{
    width: 300px;
    height: 100px;
    margin: 10px;
    border-width: 0 2px 0 2px;
    border-color: #333;
    border-style: solid;
    position: relative;
}

.first span {
    position: absolute;
    display: flex;
    right: 0;
    left: 0;
    align-items: center;
}
.first .foo{
    top: -8px;
}
.first .bar{
    bottom: -8.5px;
}
.first span:before{
    margin-right: 15px;
}
.first span:after {
    margin-left: 15px;
}
.first span:before , .first span:after {
    content: ' ';
    height: 2px;
    background: #333;
    display: block;
    width: 50%;
}


/*begin second box*/
.second{
    width: 300px;
    height: 100px;
    margin: 10px;
    border-width: 2px 0 2px 0;
    border-color: #333;
    border-style: solid;
    position: relative;
}

.second span {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.second .foo{
    left: -15px;
}
.second .bar{
    right: -15.5px;
}
.second span:before{
    margin-bottom: 15px;
}
.second span:after {
    margin-top: 15px;
}
.second span:before , .second span:after {
    content: ' ';
    width: 2px;
    background: #333;
    display: block;
    height: 50%;
}
<div class="box">
    <div class="first">
        <span class="foo">FOO</span>
        <span class="bar">BAR</span>
    </div>

   <br>

    <div class="second">
        <span class="foo">FOO</span>
        <span class="bar">BAR</span>
    </div>
</div>

1 Comment

Very good native solution, and it works very well the multiple layers and other backgrounds e.t.c
8

<fieldset>
  <legend> YOUR TITLE </legend>
  
  
  <p>
  Lorem ipsum dolor sit amet, est et illum reformidans, at lorem propriae mei. Qui legere commodo mediocritatem no. Diam consetetur.
  </p>
</fieldset>

Comments

4

You can use a fieldset tag.

<!DOCTYPE html>
<html>
<body>

<form>
 <fieldset>
  <legend>Personalia:</legend>
  Name: <input type="text"><br>
  Email: <input type="text"><br>
  Date of birth: <input type="text">
 </fieldset>
</form>

</body>
</html>

Check this link: HTML Tag

1 Comment

How is this different from the answer by Bazzz?
4

For a duplicate, here another option with transform, no fieldset ( and rounded border required in the duplicates) :

Question

enter image description here

Help. I am not great at UX. I am creating an app in React and using Material UI for the look. I really want to create something like this

Where the "Some Title" is a dynamic field from my database as well as the contents. The thing I cannot figure out is what is the best (non skanky) way to add the title into the outline? Thoughts?

Answer position or transform can help you too :

* {
  margin: 0;
  padding:0;
  box-sizing:border-box;
}

.fieldset {
  border: solid;
  color: #353fff;
  border-radius: 1em;
  margin: 2em 1em 1em;
  padding:0 1em 1em;
}

.legend {
  transform: translatey(-50%);
  width: max-content;
  background: white;
  padding: 0 0.15em;
}

.fieldset li {
  list-style-type: " - ";
}
<div class="fieldset">
  <h1 class="legend">Some Title</h1>
  <ul>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
  </ul>
</div>

2 Comments

The suggested code doesn't keep the CSS intact when the page gets resized. Whereas the same page resizing when tried using Fieldset (as suggested in the other answers) holds the CSS(box and the legend) intact. Hence, I don't think this is the suitable answer.
@Lucifer can you provide an example that breaks as you suggested :) ? ( this was an answer for stackoverflow.com/questions/63346035/… which was tagged as a duplicate of that question here ... where markup could not be a form , + rounded borders )
1

From a practical perspective, I think PeterS has the best answer. It's also presented in a very clear, didactical style.

Just to save others a few minutes converting it into more production-style code, I've done the following. Basically, it's what you would think you need: One div box inside another, with the outer div box providing the border, the inner providing the title contents with a negative margin shifting it up. A third div then contains the actual content.

.outer-border-box {
  border: 2px solid black;
  border-top: 3px solid black;
}

.label-source-box {
  padding: 0 3px;
  height: 100px;
  margin-top: -0.8em;
}

.box-title {
  background: white none repeat scroll 0 0;
  padding: 0 2px;
  margin-left: 4em;
  font-weight: 700;
  font-size: 18px;
  font-family: 'Avenir Next', Helvetica, sans-serif;
}
<div class="outer-border-box">
  <div class="label-source-box">
    <span class="box-title">Promotional </span>
    <div class="box-contents">
      <h2>this is the contents</h2>
    </div>
  </div>
</div>

Comments

1

An idea based on my code from here: https://css-tip.com/horizontal-line-title/

.box {
  --s: 3px; /* thickness of the line */
  --g: 10px; /* gap */
  --c: #000; /* colr */

  margin: 50px;
  border: var(--s) solid var(--c);
  border-top: 0;
  height: 100px;
  font-size: 20px;
  position: relative;
  clip-path: inset(-999px 0 0)
}
.box span {
  position: absolute;
  left: 10%; /* adjsut this to control the position */
  top: 0;
  translate: 0 -50%;
  border-image: 
   linear-gradient(var(--c) 0 0) 
   0 1/calc(50% - var(--s)/2) 100vw/0 calc(100vw + var(--g))
}

body {
  background: lightblue;
}
<div class="box">
  <span>Title</span>

</div>

Comments

0

If you are not in a position to add a field set, you can add a background to the element. In my situation, I had different colors in the input element and outside the input element, and also we have a hover color for the input element. So this is a fix I added linear-gradient background with outside color in the top half and transparent color in the bottom half. I added the transparent color to the bottom half inorder to see the hover color when hovered.

.class-name {
  background: linear-gradient(to bottom, #2a2b2d 50%, transparent 50%);
}

Comments

0

If you don't want to depend on the current background and have uniform padding based on font size, you can do something like this:

.square {
  position: relative;
  height: 300px;
  width: 300px;
  background: linear-gradient(-120deg, blue, yellow);
}

.square:before {
  content: '';
  position: absolute;
  inset: .5lh;
  border: solid 1px #fff;
  border-top: 0;
}

.square p {
  display: grid;
  grid-template-columns: .5lh auto minmax(.5lh,100%);
  gap: 8px;
  margin: 0 .5lh;
  color: #fff;
}

.square p:before,
.square p:after {
  content: '';
  border-top: solid 1px;
  margin-top: .5lh;
}
<div class="square">
  <p>Some text</p>
</div>

Comments

-1

It is possible by using the legend tag. Refer to http://www.w3schools.com/html5/tag_legend.asp

5 Comments

the fieldset and legend tags are not HTML5
well, they do still exist in HTML 5, so technically... they are HTML 5 tags. :)
I just want to clarify this, I think it is correct to call it HTML5 as the interface has changed since HTML4.01. The HTML5 legend interface has obsoleted the accessKey and align attributes, whereas in HTML4.01 they are only deprecated. So there is a distinction.
as I said those tags are not HTML5 those tags are HTML. the tags are not HTML5 only tags like audio is.
Link is dead :(

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.