web-dev-qa-db-fra.com

Est-il possible d'obtenir un effet de type <fieldset> sans utiliser la balise <fieldset>?

Personnellement, j’aime bien le tag <fieldset> en raison de la façon dont il dessine une boîte et place le <legend> en haut, au-dessus de la bordure. Comme ça.

example image of what I'm trying to achieve

Cependant, l'élément fieldset a été créé pour organiser formulaires , et son utilisation pour la conception générale n'est pas meilleure que l'utilisation de tableaux pour la conception générale. Donc, ma question est ... comment puis-je obtenir le même résultat en utilisant une autre balise? La bordure doit être effacée sous le <legend> (ou toute autre balise qui sera utilisée), et puisqu’il pourrait y avoir une image de fond de corps "complexe", je ne peux pas me permettre de définir le background-color de la légende pour qu’il corresponde à celui de la légende. l'un des éléments sous.

J'aimerais que cela fonctionne sans JavaScript, mais les formats CSS3 et XML (tels que SVG ou XHTML) conviennent.

49
zneak

Non, ce n'est pas vraiment possible. Même les fabricants de navigateurs eux-mêmes ont du mal à cela.

Bien sûr, je n'ai pas pu m'empêcher de tenter ma chance quand même. Et j'ai passé tellement de temps là-dessus que Anonyme est arrivé à une "solution" assez semblable à la mienne (son test1). Mais le mien n'a pas besoin de la "légende" de largeur fixe.

Ce code est évidemment un peu bidouillé, cependant, et je ne sais pas à quel point il se comportera bien sur des sites complexes. Je suis également d’accord avec Anonyme pour dire que l’utilisation d’un groupe de champs pour le regroupement n’est pas aussi grave que l’utilisation de tableaux pour la présentation. Les champs étaient conçus pour regrouper des éléments, bien qu'en HTML ils ne soient réellement censés être utilisés que pour regrouper des contrôles de formulaire.

.fieldset {
  border: 2px groove threedface;
  border-top: none;
  padding: 0.5em;
  margin: 1em 2px;
}

.fieldset>h1 {
  font: 1em normal;
  margin: -1em -0.5em 0;
}

.fieldset>h1>span {
  float: left;
}

.fieldset>h1:before {
  border-top: 2px groove threedface;
  content: ' ';
  float: left;
  margin: 0.5em 2px 0 -1px;
  width: 0.75em;
}

.fieldset>h1:after {
  border-top: 2px groove threedface;
  content: ' ';
  display: block;
  height: 1.5em;
  left: 2px;
  margin: 0 1px 0 0;
  overflow: hidden;
  position: relative;
  top: 0.5em;
}
<fieldset>
  <legend>Legend</legend> Fieldset
</fieldset>

<div class="fieldset">
  <h1><span>Legend</span></h1> Fieldset
</div>

En guise de remarque, vous pouvez également consulter les éléments HTML5 figure et figcaption . Ceux-ci semblent être les meilleurs éléments à utiliser dans votre exemple.

Cela ne concerne toutefois que la partie sémantique du problème, car je ne pense pas que ces éléments soient rendus de la même manière qu’un champ/une légende. Sans compter que les navigateurs actuels ne prennent probablement pas en charge ces éléments.

17
mercator

Lien de démonstration jsBin 

.fieldset {
  border: 1px solid #ddd;
  margin-top: 1em;
  width: 500px;
}

.fieldset h1 {
  font-size: 12px;
  text-align: center;
}

.fieldset h1 span {
  display: inline;
  border: 1px solid #ddd;
  background: #fff;
  padding: 5px 10px;
  position: relative;
  top: -1.3em;
}
<div class="fieldset">
  <h1><span>Title</span></h1>
  <p>Content</p>
</div>

45
Mathias Bynens

Cependant, il a été fait pour organiser formes, et en utilisant pour la conception générale n’est pas mieux que d’utiliser des tables pour conception générale

Ceci est une erreur. Le principal problème lié à l'utilisation de tableaux pour la mise en forme est que presque aucune disposition ne correspond à des données tabulaires. Le deuxième problème est qu'aucun de ceux qui ne mappent pas avec des données tabulaires ne sont des données tabulaires, et d'autres qui ne le sont pas. C'est-à-dire que la sémantique du balisage ne correspond pas à celle de la page. De plus, de manière pragmatique, le mécanisme de disposition des tableaux rend le style personnalisé et la navigation en mode texte uniquement douloureux ou impossible.

Maintenant, fieldset a clairement l'intention de regrouper les champs de formulaire. Et choisir un élément pour son apparence est presque toujours le signe que c'est un mauvais choix. Cependant, pour cet exemple spécifique, je dirais qu’un fieldset + une légende contenant une liste n’a pratiquement aucun inconvénient (en fait, le seul auquel je puisse penser est un scaper qui interprète naïvement fieldset comme un moyen de signaler un formulaire son contenu différemment, mais je ne connais rien qui le fasse réellement). La raison principale en est que l'élément de formulaire remplit le rôle fonctionnel et sémantique de contenir des entrées, alors que les champs possédés depuis le début présentaient des effets spéciaux spéciaux, non reproductibles. De plus, si les éléments visuels du fieldset sont fonctionnels de quelque manière que ce soit, le fieldset contient à nouveau un ensemble de widgets interactifs, qui était le point d'origine.

Mon conseil est de l'utiliser si vous le souhaitez. Je ne le ferais pas, mais pas à cause de considérations sémantiques: je préfère ne pas compter sur des effets spéciaux et éviter la forme plutôt que la fonction en général.

Quoi qu'il en soit, voici quelque chose à mâcher:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>test</title><style type="text/css">

.fake_fieldset {
	border: 2px groove ButtonFace;
	border-top-width: 0;
	margin-left: 2px;
	margin-right: 2px;
	padding: .35em .625em .75em;
	margin-top: 1em;
	position: relative;
}

.fake_legend {
	margin-top: -1em;
}

.fake_legend.test1::before {
	position: absolute;
	top: 0;
	left: -1px;
	border-top: 2px groove ButtonFace;
	content: " ";
	width: 0.5em;
}

.fake_legend.test1::after {
	position: absolute;
	top: 0;
	right: -1px;
	border-top: 2px groove ButtonFace;
	content: " ";
	width: 80%;
}


.fake_fieldset.test2 {
	padding: 0;
	padding-top: 1px; /* no collapsed margin */
}

.fake_fieldset.test2 .fake_fieldset.container {
	margin: 0;
	border: 0;
}

.fake_legend.test2 {
	display: table;
	width: 100%;
}

.fake_legend.test2 span {
	display: table-cell;
}

.fake_legend.test2 span:first-child {
	width: 0.5em;
}
.fake_legend.test2 span:first-child + span {
	width: 0; /* cells stretch */
}
.fake_legend.test2 span:first-child,
.fake_legend.test2 span:last-child {
	/* the rest of this code is left as an exercise for the reader */
}


</style></head><body>

<fieldset><legend>foo</legend>bar</fieldset>

<div class="fake_fieldset test1"><div class="fake_legend test1">foo</div>bar</div>

<div class="fake_fieldset test2"><div class="fake_legend test2"><span></span><span>foo</span><span></span></div><div class="fake_fieldset container">bar</div></div>

</body></html>

6
Anonymous

Voici une solution possible en mettant l'accent sur la simplicité (si vous pouvez perdre un peu votre exigence de fond transparent). Aucun élément supplémentaire.

section {
  border: 2px groove threedface;
  padding: 1em;
}

section h2 {
  float: left;
  margin: -1.7em 0 0;
  padding: 0 .5em;
  background: #fff;
  font-size: 1em;
  font-weight: normal;
}
<section id=foo>
  <h2>
    Foo
  </h2>
  bar
</section>

1
untill

Je mets à jour un peu la proposition d'Anonymous à cela:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>test</title><style type="text/css">

.fake_fieldset {
    border: 2px groove ButtonFace;
    border-top-width: 0;
    margin-left: 2px;
    margin-right: 2px;
    padding: .35em .625em .75em;
    margin-top: 1em;
    position: relative;
}

.fake_legend {
    margin-top: -1em;
}

.fake_legend.test1::before {
    position: absolute;
    top: 0;
    left: -1px;
    border-top: 2px groove ButtonFace;
    content: " ";
    width: 0.5em;
}

.fake_legend.test1::after {
    position: absolute;
    top: 0;
    right: -1px;
    border-top: 2px groove ButtonFace;
    content: " ";
    width: 80%;
}
.fake_legend.test1 div {
    z-index: 100;
    background: white;
    position: relative;
    float: left;
}


.fake_fieldset.test2 {
    padding: 0;
    padding-top: 1px; /* no collapsed margin */
}

.fake_fieldset.test2 .fake_fieldset.container {
    margin: 0;
    border: 0;
}

.fake_legend.test2 {
    display: table;
    width: 100%;
}

.fake_legend.test2 span {
    display: table-cell;
}

.fake_legend.test2 span:first-child {
    width: 0.5em;
}
.fake_legend.test2 span:first-child + span {
    width: 0; /* cells stretch */
}
.fake_legend.test2 span:first-child,
.fake_legend.test2 span:last-child {
    /* the rest of this code is left as an exercise for the reader */
}
</style></head><body>

<fieldset><legend>foo</legend>bar</fieldset>

<div class="fake_fieldset test1"><div class="fake_legend test1">foo</div>bar</div>

<div class="fake_fieldset test2"><div class="fake_legend test2"><span></span><span>foo</span><span></span></div><div class="fake_fieldset container">bar</div></div>

</body></html>
0
Mickael Dubois

Je crois que vous connaissez déjà la réponse.

Vous avez 2 options, fournir votre propre bordure (ce qui représente beaucoup de travail inutile) ou positionner un élément avec une occlusion de la bordure (le problème est que vous ne pouvez avoir qu'une couleur de fond unie, mais peut-être que ça va).

À ma connaissance, vous ne pouvez rien faire pour rendre cet entraînement agréable dans tous les navigateurs. J'aime ton style, c’est la bonne approche, mais ce n’est probablement pas un problème que tu pourras résoudre de manière satisfaisante.

Mon opinion générale sur ces sujets est qu'il ne faut pas essayer de faire avec le Web des choses qui nécessitent A) des efforts excessifs ou B) une solution de balisage qui ne soit pas tout à fait évident pour commencer. Le Web a des limites et vous feriez bien de vous en occuper plutôt que d'essayer de les contourner.

Je suis donc obligé de demander: quel est le problème avec <légende />?

0
John Leidegren

Utilisez le pseudoélément ::before pour générer la bordure supérieure du <fieldset> émulé, puis positionnez l'élément <legend> émulé sur le bloc ::before avec les propriétés z-index et position. Enfin, utilisez un dégradé et une couleur unie sur la partie supérieure du groupe de champs émulé, en définissant la couleur supérieure du dégradé linéaire sur transparent de manière à ce que l'arrière-plan situé derrière le groupe de champs fictif soit visible.

0
Khayri R.R. Woulfe

J'ai eu un résultat raisonnable. 

    <div>
      <div style='position:absolute;float:top;background-image: url("whiteSquare.jpg");height:20px;z-index:10;font-size:20px'>
            Header
        </div>
        
         <div style='position:absolute;float:top;border:1px dashed gray;width:300px;margin-top:12px;z-index:1'>
             <div style='margin-top:20px;'>
             <table>
              <tr>
                  <td>A</td>
                  <td>B</td>
                 </tr>
                 <tr>
                  <td>A</td>
                  <td>B</td>
                 </tr>
             </table>
             </div>
        </div>
    </div>

0