skip to Main Content

I’m in the process of building an input in a form that contains a profile picture that, when clicked, will allow a user to select a new image. It looks like the common practice is to use an input with the type of "file" and then hide it through various means. Setting opacity:0 seems to be the only legitimate option to me, as this will keep the element in the DOM and it will still detect clicks or focus.

However, an input with no opacity will also not have a visible focus ring, even though the element is technically in focus. What are the options I have at my disposal in order to have a focus ring show when focused? Thank you in advance.

.profile-pic {
  width: 156px;
  height: 156px;
  border-radius: 50%;
  position: relative;
  /* overflow: hidden; */
}

.profile-pic input[type='file'] {
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  z-index: 10;
}

.profile-pic__img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  overflow: hidden;
  z-index: 1;
}

.profile-pic__img img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.65);
  transition: filter 0.2s ease-in-out;
  cursor: pointer;
}

.profile-pic__img img:hover {
  filter: brightness(0.5);
}

.profile-pic__text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 90%;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 5;
}

.profile-pic__text .fa-camera {
  color: #fff;
}

.profile-pic span {
  color: #fff;
  text-align: center;
  font-size: 16px;
  font-style: normal;
  font-weight: 400;
  line-height: normal;
  width: 90%;
}
<div class="profile-pic">
  <input type="file" />
  <div class="profile-pic__img">
    <img src="[TEST_URL]" alt="" />
  </div>
  <div class="profile-pic__text">
    <i class="fas fa-camera"></i>
    <span>Click to change photo</span>
  </div>
</div>

3

Answers


  1. Apply the :focus-within pseudo-class to the .profile-pic and give it distinctive styling when the transparent input has the focus.

    .profile-pic {
      width: 156px;
      height: 156px;
      border-radius: 50%;
      position: relative;
      /* overflow: hidden; */
    }
    
    .profile-pic:focus-within {
        outline: dotted #777 2px;
    }
    
    .profile-pic input[type='file'] {
      opacity: 0;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      padding: 0;
      border: none;
      border-radius: 50%;
      cursor: pointer;
      z-index: 10;
    }
    
    .profile-pic__img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      overflow: hidden;
      z-index: 1;
    }
    
    .profile-pic__img img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      filter: brightness(0.65);
      transition: filter 0.2s ease-in-out;
      cursor: pointer;
    }
    
    .profile-pic__img img:hover {
      filter: brightness(0.5);
    }
    
    .profile-pic__text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 90%;
      display: flex;
      flex-direction: column;
      align-items: center;
      z-index: 5;
    }
    
    .profile-pic__text .fa-camera {
      color: #fff;
    }
    
    .profile-pic span {
      color: #fff;
      text-align: center;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: normal;
      width: 90%;
    }
    <div class="profile-pic">
      <input type="file" />
      <div class="profile-pic__img">
        <img src="[TEST_URL]" alt="" />
      </div>
      <div class="profile-pic__text">
        <i class="fas fa-camera"></i>
        <span>Click to change photo</span>
      </div>
    </div>
    Login or Signup to reply.
  2. Basically the same answer as Quentin’s, except I wanted to keep the pseudo-class applied to the input, so I used a box-shadow rather than a outline. Six of one, half-dozen of another.

    .profile-pic {
      width: 156px;
      height: 156px;
      border-radius: 50%;
      position: relative;
      /* overflow: hidden; */
    }
    
    .profile-pic input[type='file'] {
      opacity: 0.2;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      padding: 0;
      border: none;
      border-radius: 50%;
      cursor: pointer;
      z-index: 10;
    }
    
    .profile-pic input[type='file']:focus-within {
      box-shadow: 0 0 1px 5px blue;
    }
    
    .profile-pic__img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      overflow: hidden;
      z-index: 1;
    }
    
    .profile-pic__img img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      filter: brightness(0.65);
      transition: filter 0.2s ease-in-out;
      cursor: pointer;
    }
    
    .profile-pic__img img:hover {
      filter: brightness(0.5);
    }
    
    .profile-pic__text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 90%;
      display: flex;
      flex-direction: column;
      align-items: center;
      z-index: 5;
    }
    
    .profile-pic__text .fa-camera {
      color: #fff;
    }
    
    .profile-pic span {
      color: #fff;
      text-align: center;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: normal;
      width: 90%;
    }
    <div class="profile-pic">
      <input type="file" />
      <div class="profile-pic__img">
        <img src="[TEST_URL]" alt="" />
      </div>
      <div class="profile-pic__text">
        <i class="fas fa-camera"></i>
        <span>Click to change photo</span>
      </div>
    </div>
    Login or Signup to reply.
  3. I’m not sure if you need an invisible element to have a focus ring, if it’s invisible.

    You could add a focus ring to your .profile-pic element instead, because it’s actually visible and visually interactive.

    You can make your .profile-pic element focusable by adding a tabindex="0" attribute to it. Then just select it in CSS via .profile-pic:focus and design a focus ring.

    I know I haven’t really answered your question, but I hope this helps.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search