Avatar Animation | Html Css And JavaScipt WIth Free Source Code

Follow Us On Telegram   Telegram link

This free source code allows you to create a simple and interactive animated avatar on your website.

The avatar is designed using HTML and CSS, and the animation is powered by JavaScript.

The avatar moves horizontally across the screen in a smooth and continuous loop.

You can customize the avatar's appearance by adjusting the background color, size, and animation properties in the CSS code.

Feel free to use this code snippet to enhance the visual appeal of your website and engage your users.

To access the complete source code and implementation details, please visit codeatnow.com.

Download Code

HTML
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>CodeAtNow - Avatar Input</title>
  <link rel="stylesheet" href="./style.css">

</head>
<body>
<!-- partial:index.partial.html -->
<div class="avatar-input">
  <label class="avatar-input__label" for="file-input">
    <input type="file" id="file-input" class="avatar-input__input" />
    <div class="avatar-input__icon">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 460.8 460.8"
        fill="currentColor"
      >
        <path
          d="M230.432,239.282c65.829,0,119.641-53.812,119.641-119.641C350.073,53.812,296.261,0,230.432,0
        S110.792,53.812,110.792,119.641S164.604,239.282,230.432,239.282z"
        />
        <path
          d="M435.755,334.89c-3.135-7.837-7.314-15.151-12.016-21.943c-24.033-35.527-61.126-59.037-102.922-64.784
        c-5.224-0.522-10.971,0.522-15.151,3.657c-21.943,16.196-48.065,24.555-75.233,24.555s-53.29-8.359-75.233-24.555
        c-4.18-3.135-9.927-4.702-15.151-3.657c-41.796,5.747-79.412,29.257-102.922,64.784c-4.702,6.792-8.882,14.629-12.016,21.943
        c-1.567,3.135-1.045,6.792,0.522,9.927c4.18,7.314,9.404,14.629,14.106,20.898c7.314,9.927,15.151,18.808,24.033,27.167
        c7.314,7.314,15.673,14.106,24.033,20.898c41.273,30.825,90.906,47.02,142.106,47.02s100.833-16.196,142.106-47.02
        c8.359-6.269,16.718-13.584,24.033-20.898c8.359-8.359,16.718-17.241,24.033-27.167c5.224-6.792,9.927-13.584,14.106-20.898
        C436.8,341.682,437.322,338.024,435.755,334.89z"
        />
      </svg>
    </div>
  </label>
</div>
<!-- partial -->
  <script  src="./script.js"></script>

</body>
</html>
CSS
* {
  box-sizing: border-box;
}

:root {
  --background-color: #11131e;
  --shadow-color: #030305;
  --input-bg-color: hsl(208.7, 20%, 80%);
  --input-icon-color: hsl(208.7, 20%, 50%);
  --outline-color: hsl(208.7, 100%, 50%);
  --check-color: hsl(202, 100%, 53%);
  background-color: var(--background-color);
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.avatar-input {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: 0.2s ease all;
  width: 150px;
  height: 150px;
  padding: 4px;
  position: relative;
}

.avatar-input__label {
  box-shadow: 0 20px 25px -5px var(--shadow-color),
    0 8px 10px -6px var(--shadow-color);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  position: relative;
  transition: 0.4s ease all;

  overflow: hidden;

  cursor: pointer;
  z-index: 1;
}

.avatar-input--dragover,
.avatar-input--uploading,
.avatar-input--success,
.avatar-input:active {
  transform: scale(0.9);
}

.avatar-input:active .avatar-input__label {
  box-shadow: none;
}

.avatar-input--dragover .avatar-input__label,
.avatar-input--uploading .avatar-input__label,
.avatar-input--success .avatar-input__label {
  box-shadow: none;
  filter: brightness(0.5);
}

.avatar-input__input {
  display: none;
}

.avatar-input__icon {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
  color: var(--input-icon-color);
  background: var(--input-bg-color);
  transition: 0.2s ease all;
}

.avatar-input__icon svg {
  width: 80%;
  position: relative;
  bottom: -6%;
}

.avatar-input__preview {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  object-fit: cover;
  width: 100%;
  height: 100%;
  transition: 0.2s ease all;
  transform: scale(1.05);
}

.avatar-input__outline {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  stroke-opacity: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  color: var(--outline-color);
  stroke-dasharray: var(--outline-total-stroke) var(--outline-stroke-offset);
  stroke-dashoffset: var(--outline-total-stroke);
  transition: 0.05s linear all;
  pointer-events: none;
}

.avatar-input--uploading .avatar-input__outline,
.avatar-input--success .avatar-input__outline {
  stroke-opacity: 1;
}

.avatar-input--uploading .avatar-input__percentage {
  opacity: 1;
}

.avatar-input__percentage {
  position: absolute;
  opacity: 0;
  z-index: 2;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: Arial, Helvetica, sans-serif;
  color: white;
  font-weight: bold;
  transition: 0.25s ease opacity;
  pointer-events: none;
}

.avatar-input__success {
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: Arial, Helvetica, sans-serif;
  color: white;
  transition: 0.25s ease opacity;
  width: 40%;
  pointer-events: none;
}

.avatar-input__success-icon {
  stroke-dasharray: var(--check-total-stroke) var(--check-total-stroke);
  stroke-dashoffset: var(--check-stroke-offset);
  opacity: 0;
  transition: 0.4s ease all;
  transition-delay: 100ms;
  color: var(--check-color);
}

.avatar-input--success .avatar-input__success-icon {
  opacity: 1;
}
JS
class AvatarInput {
  percentage = 0

  constructor(el) {
    this.root = el
    this.label = el.querySelector('.avatar-input__label')
    this.input = el.querySelector('.avatar-input__input')
    this.addOutline()
    this.addPercentageText()
    this.addPreviewImage()
    this.addSuccessMessage()

    this.root.addEventListener('dragover', this.onDragOver.bind(this))
    this.root.addEventListener('dragleave', this.onDragLeave.bind(this))
    this.root.addEventListener('drop', this.onDrop.bind(this))

    this.reader = new FileReader()
    this.reader.addEventListener('load', this.onFileRead.bind(this))

    this.input.addEventListener('input', this.onFileSelect.bind(this))
  }

  onDragOver(e) {
    e.preventDefault()
    this.root.classList.add('avatar-input--dragover')
  }

  onDragLeave() {
    this.removeDragoverState()
  }

  removeDragoverState() {
    this.root.classList.remove('avatar-input--dragover')
  }

  addPercentageText() {
    this.percentageText = document.createElement('div')
    this.percentageText.classList.add('avatar-input__percentage')
    this.percentageText.textContent = '0%'
    this.percentageText.style.fontSize = `${this.root.clientWidth * 0.2}px`
    this.root.appendChild(this.percentageText)
  }

  startUploading() {
    setTimeout(() => {
      this.uploadTick()
    }, 600)
  }

  addSuccessMessage() {
    this.success = document.createElement('div')
    this.success.classList.add('avatar-input__success')

    this.successSvg = document.createElementNS(
      'http://www.w3.org/2000/svg',
      'svg'
    )
    this.successSvg.setAttribute('viewBox', '0 0 24 24')
    this.successSvg.classList.add('avatar-input__success-icon')

    const svgIcon = document.createElementNS(
      'http://www.w3.org/2000/svg',
      'path'
    )

    svgIcon.setAttribute(
      'd',
      'M3.36902 12.4213L9.0003 18.0527C9.20134 18.2537 9.52933 18.2469 9.72183 18.0376L20.8689 5.92126'
    )
    svgIcon.setAttribute('stroke', 'currentColor')
    svgIcon.setAttribute('stroke-width', '2')
    svgIcon.setAttribute('stroke-linecap', 'round')
    svgIcon.setAttribute('fill', 'none')

    this.successSvg.appendChild(svgIcon)
    this.success.appendChild(this.successSvg)

    this.root.appendChild(this.success)

    this.totalCheckStrokeLength = Math.ceil(svgIcon.getTotalLength()) + 2
    this.successSvg.style.setProperty(
      '--check-stroke-offset',
      this.totalCheckStrokeLength
    )
    this.successSvg.style.setProperty(
      '--check-total-stroke',
      this.totalCheckStrokeLength
    )
  }

  onDone() {
    this.root.classList.remove('avatar-input--uploading')
    this.successSvg.style.setProperty('--check-stroke-offset', 0)
    this.root.classList.add('avatar-input--success')
    setTimeout(() => {
      this.percentage = 0
      this.updateText()
    }, 200)

    setTimeout(() => {
      this.successSvg.style.setProperty(
        '--check-stroke-offset',
        this.totalCheckStrokeLength
      )
    }, 800)

    setTimeout(() => {
      this.root.classList.remove('avatar-input--success')
      this.updateOutline()
    }, 1200)
  }

  uploadTick() {
    if (this.percentage === 100) {
      setTimeout(() => {
        this.onDone()
      }, 400)
      return
    }
    this.percentage++
    this.updateOutline()
    this.updateText()
    requestAnimationFrame(this.uploadTick.bind(this))
  }

  updateText() {
    this.percentageText.textContent = this.percentage + '%'
  }

  updateOutline() {
    this.outline.style.setProperty(
      '--outline-stroke-offset',
      this.totalOutlineStrokeLength -
        this.totalOutlineStrokeLength * this.percentage * 0.01
    )
  }

  addOutline() {
    const rootWidth = this.root.clientWidth
    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')

    svg.setAttribute('viewBox', `0 0 ${rootWidth} ${rootWidth}`)
    svg.classList.add('avatar-input__outline')

    const svgCircle = document.createElementNS(
      'http://www.w3.org/2000/svg',
      'circle'
    )
    svgCircle.setAttribute('cx', '50%')
    svgCircle.setAttribute('cy', '50%')
    svgCircle.setAttribute('r', rootWidth / 2 - 3)
    svgCircle.setAttribute('fill', 'none')
    svgCircle.setAttribute('stroke', 'currentColor')
    svgCircle.setAttribute('stroke-width', '3px')

    svg.appendChild(svgCircle)
    this.outline = svg
    this.root.appendChild(svg)

    this.totalOutlineStrokeLength = Math.ceil(svgCircle.getTotalLength()) + 2
    svg.style.setProperty(
      '--outline-stroke-offset',
      this.totalOutlineStrokeLength
    )
    svg.style.setProperty(
      '--outline-total-stroke',
      this.totalOutlineStrokeLength
    )
  }

  onDrop(e) {
    e.preventDefault()
    const items = [...e.dataTransfer.items]
    if (!items || items?.[0].kind !== 'file') return
    const file = items[0].getAsFile()
    this.reader.readAsDataURL(file)
    setTimeout(() => {
      this.removeDragoverState()
      this.root.classList.add('avatar-input--uploading')
    }, 300)
  }

  onFileSelect() {
    const file = this.input.files[0]
    if (file) {
      this.root.classList.add('avatar-input--uploading')
      this.reader.readAsDataURL(file)
    }
  }

  setPreviewImage(src) {
    this.previewImage.src = src
  }

  addPreviewImage() {
    this.previewImage = document.createElement('img')
    this.previewImage.classList.add('avatar-input__preview')
    this.label.appendChild(this.previewImage)
  }

  onFileRead() {
    const image = this.reader.result
    this.setPreviewImage(image)
    this.startUploading()
  }
}

Array.from(document.querySelectorAll('.avatar-input')).forEach(
  (el) => new AvatarInput(el)
)

Post a Comment

0Comments
Post a Comment (0)