Search code examples
javascripthtmlcssflexbox

How do I prevent a button from shrinking when its content changes without setting a width?


I have several form buttons positioned in a div using display: flex.

enter image description here

Upon clicking the "Save" button I want to hide the original content of the save button and show a centered spinning icon. However, I do not want the width of the button to change since that causes the page other elements (buttons) around it to shift. Here's what happens with that I have now:

enter image description here

How do I ensure that the button keeps it's original width and does not shrink? I know I could set a min-width on the button, but that would require me to specify a different width for each button this behavior is on since the text could be shorter or longer each time. I have also tried adding various combinations of flex-shrink: 0 styles to the buttons, but that doesn't seem to work either.

Code Pen Example

https://codepen.io/kspearrin/pen/eVNeMX

HTML

<div class="wrapper">
  <button type="button" id="save">
    <span id="savetext"><i class="fa fa-save"></i> Save</span>
    <i class="fa fa-spinner fa-spin hide" id="spinner"></i>
  </button>
  <button type="button" id="cancel">Cancel</button>
  <div class="right">
    <button type="button"><i class="fa fa-star"></i></button>
    <button type="button"><i class="fa fa-trash"></i></button>
  </div>
</div>

CSS

.wrapper {
  display: flex;
  width: 400px;
  align-items: center;
  background-color: lightblue;
  padding: 10px;
}

button {
  margin-right: 10px;
  text-align: center;
  padding: 5px 10px;
}

button:last-child {
  margin-right: 0;
}

.right {
  margin-left: auto;
  display: flex;
  align-items: center;
}

.hide {
  display: none;
}

JS

document.getElementById("save").onclick = () => {
  document.getElementById("savetext").classList.add("hide");
  document.getElementById("spinner").classList.remove("hide");
};

document.getElementById("cancel").onclick = () => {
  document.getElementById("savetext").classList.remove("hide");
  document.getElementById("spinner").classList.add("hide");
};

Solution

  • As said in comments, it is not related to flexbox: the behavior is normal. A box that is not display will fit its content width.

    You can use visibility and flexbox to set the layout of your spinner. Here, I just set the upper div to position:relative, it does nothing except it becomes the reference for #spinner which is absolute. I stretch it to the maximum and center its content with the flexbox :)

    document.getElementById("save").onclick = () => {
      document.getElementById("savetext").classList.add("hide");
      document.getElementById("spinner").classList.remove("hide");
    };
    
    document.getElementById("cancel").onclick = () => {
      document.getElementById("savetext").classList.remove("hide");
      document.getElementById("spinner").classList.add("hide");
    };
    .wrapper {
      display: flex;
      width: 400px;
      align-items: center;
      background-color: lightblue;
      padding: 10px;
    }
    
    button {
      margin-right: 10px;
      text-align: center;
      padding: 5px 10px;
    }
    
    button:last-child {
      margin-right: 0;
    }
    
    .right {
      margin-left: auto;
      display: flex;
      align-items: center;
    }
    
    .hide {
      visibility: hidden;
    }
    
    #save {
      position: relative;
    }
    
    #spinner {
     position: absolute;
     display: flex;
     align-items: center;
     justify-content: center;
     bottom: 0;
     top: 0;
     left: 0;
     right: 0;
    }
    <div class="wrapper">
      <button type="button" id="save">
        <span id="savetext"><i class="fa fa-save"></i> Save</span>
        <i class="fa fa-spinner fa-spin hide" id="spinner"></i>
      </button>
      <button type="button" id="cancel">Cancel</button>
      <div class="right">
        <button type="button"><i class="fa fa-star"></i></button>
        <button type="button"><i class="fa fa-trash"></i></button>
      </div>
    </div>

    The updated codepen (font-awesome does not work here): https://codepen.io/anon/pen/vdOpJd