Home > Back-end >  Ignore label elements when center-aligning form
Ignore label elements when center-aligning form

Time:07-12

I am creating a form for my site that is center-aligned on my page. However, I want to ignore the labels when center aligning, such that the input boxes are center-aligned, with the labels right aligned up-against the inputs.

Here is a simplified snippet from my code, just to display the issue.

body {
text-align: center;
}
<!DOCTYPE html>
<html>
<body>

<h1>Login</h1>

<form>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>

    <br><br>

    <label for="password">Password:</label>
    <input type="password" id="password" name="password" required>

    <br><br>

    <button class = 'button' id ='loginbutton' type="submit">Login</button>
</form>

</body>
</html>

By reading other questions, I saw one recommendation of setting the display to inline block and the width to 0. That properly aligned my input boxes, but my labels are now behind the text.

body {
text-align: center;
}

label {
display: inline-block;
width: 0;
}
<!DOCTYPE html>
<html>
<body>

<h1>Login</h1>

<form>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>

    <br><br>

    <label for="password">Password:</label>
    <input type="password" id="password" name="password" required>

    <br><br>

    <button class = 'button' id ='loginbutton' type="submit">Login</button>
</form>

</body>
</html>

I know I could achieve this through a table, but I was wondering if there was any simpler way? Here is the code showing my desired look.

body {
    text-align: center;
 }

#table-form {
    display: flex;
    justify-content: center;
    text-align: right;
 }

 td {
    width: 10rem
 }
<!DOCTYPE html>
<html>
<body>

<h1>Login</h1>

<form>
  <div id = 'table-form'>
    <table>
       <tr>
          <td> <label for="email">Email:</label> </td>
          <td> <input type="email" id="email" name="email" required> </td>
          <td> </td>
        </tr>
        
        <tr>
          <td> <label for="password">Password:</label> </td>
          <td> <input type="password" id="password" name="password" required> </td>
          <td> </td>
        </tr>
     </table>
   </div>
   
   <br>
   
   <button class = 'button' type="submit">Login</button>

</form>

</body>
</html>

If the table is the best way to address this, just let me know :) Thanks for the help!

CodePudding user response:

One approach, with explanatory comments in the code, is below:

/* we use this width a couple of times, so we cache it as
   a CSS custom property (to allow for easier updating in
   the future): */
:root {
  --inputWidth: 15em;
}


/* hugely simple/naive reset, to have all elements' dimensions
   calculated as including the width of borders and padding, and
   removing default margin and padding: */
*,
 ::before,
 ::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}


/* to center align: */
h1 {
  text-align: center;
}


/* using flex-layout: */
form {
  display: flex;
  /* shorthand for:
      flex-direction: column;
      flex-wrap: nowrap;
  */
  flex-flow: column nowrap;
  /* shorthand for:
      justify-content: center;
      align-content: center;
  */
  place-items: center;
  /* to place a 2em gap between adjacent elements,
     whether horizontally or vertically; shorthand for:
      gap: 2em 2em;
     which is shorthand for:
      column-gap: 2em;
      row-gap: 2em;
  */
  gap: 2em;
  /* applies a margin along the block axis (in a
     language such as English that's top and bottom): */
  margin-block: 1em;
  /* applies an auto margin along the inline axis (in a
     language such as English that's left and right), this
     causes the <form> element to be centered on the inline
     axis: */
  margin-inline: auto;
  /* using the clamp() function to set a preferred width
     of 60vw, with a minimum permitted width of 20em and
     a maximum permitted width of 1000px: */
  width: clamp(20em, 60vw, 1000px);
}

label {
  /* centering the content of the <label> element: */
  justify-content: center;
  /* using flex layout: */
  display: flex;
  /* and assigning a position of relative, in order
     to absolutely position a descendant: */
  position: relative;
}

label > span {
  /* position: absolute takes the element out of the
     document flow and layout calculations: */
  position: absolute;
  /* aligning the text to the end of the inline axis,
     in English that's equivalent to 'right': */
  text-align: end;
  /* translating the element 95% of its own width,
     the -95% moves it towards the start of the
     inline axis (left in a left-to-right language): */
  transform: translateX(-95%);
  /* setting the width to be equal to the width of
     the <input>: */
  width: var(--inputWidth);
}


/* styling the pseudo-element to automatically display
   a presentational ':' character following the 
   content: */
label > span::after {
  content: ':';
}

input {
  width: var(--inputWidth);
}


/* styling the <button> so as not to have it span the full
   width of the flex parent: */
button {
  padding-block: 0.25em;
  padding-inline: 0.5em;
  width: fit-content;
}
<h1>Login</h1>

<form>
  <!-- I've moved the <input> inside the <label>, and wrapped its text-content in a <span> for
       styling purposes: -->
  <label for="email">
    <span>Email</span>
    <input type="email" id="email" name="email" required>
    </label>
  <label for="password">
  <span>Password</span>
  <input type="password" id="password" name="password" required>
  </label>
  <button class='button' id='loginbutton' type="submit">Login</button>
</form>

JS Fiddle demo.

References:

  • Related