Floating Label Form với UIkit: Label bay lên khi nhập, gọn đẹp và dễ đọc

Floating Label giúp trường nhập liệu gọn gàng: nhãn nằm trong ô khi trống và trượt lên phía trên khi người dùng nhập. Kỹ thuật này cải thiện khả năng quét thông tin, tiết kiệm diện tích, và giảm nhầm lẫn giữa placeholder và label. Bài viết hướng dẫn bạn xây dựng Floating Label dùng UIkit với CSS hiện đại, hỗ trợ dark mode và tương thích autofill của trình duyệt.

Floating Label Form với UIkit: Label bay lên khi nhập, gọn đẹp và dễ đọc

Bước 1: Tạo cấu trúc HTML cho mỗi trường

Mỗi input đặt trong một wrapper .im-float gồm: label, input/textarea và icon tùy chọn. Label đặt sau input để dùng selector anh em kế tiếp.

<div class="im-float uk-form-stacked">
  <div class="uk-form-controls uk-position-relative">
    <input class="uk-input" type="text" id="name" placeholder=" " autocomplete="name">
    <label for="name" class="im-float-label">Họ và tên</label>
    <span class="uk-form-icon" aria-hidden="true" uk-icon="user"></span>
  </div>
</div>

Bước 2: Viết CSS cho hiệu ứng bay và trạng thái

Hiệu ứng dựa trên hai trạng thái: khi ô trống dùng :placeholder-shown, khi người dùng tương tác dùng :focus-within. Với dark mode, đồng bộ theo .uk-dark hoặc .dark.

/* ===== Floating Label for UIkit ===== */
.im-float { margin-bottom: 16px; }

.im-float .uk-form-controls { /* giữ label vị trí tuyệt đối */
  position: relative;
}

/* Label nổi */
.im-float-label {
  position: absolute;
  left: 44px;               /* chừa khoảng cho icon trái (24px + padding) */
  top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  line-height: 1;
  color: var(--im-label, #888);
  pointer-events: none;
  transition: transform 160ms ease, top 160ms ease, font-size 160ms ease, color 160ms ease, left 160ms ease;
}

/* Input/textarea base */
.im-float .uk-input,
.im-float .uk-textarea,
.im-float .uk-select {
  padding-left: 44px;       /* để icon + label không đè vào text */
  padding-right: 12px;
  height: 44px;
}

/* Textarea cao hơn và canh label */
.im-float .uk-textarea {
  height: auto;
  min-height: 120px;
  padding-top: 22px;
}

/* Khi focus hoặc có giá trị: label thu nhỏ và bay lên trên */
.im-float:focus-within .im-float-label,
.im-float .uk-input:not(:placeholder-shown) + .im-float-label,
.im-float .uk-textarea:not(:placeholder-shown) + .im-float-label,
.im-float .has-value + .im-float-label {
  top: 6px;
  transform: none;
  font-size: 12px;
  color: var(--im-label-active, #666);
}

/* Có icon bên phải */
.im-float.icon-right .im-float-label { left: 12px; }
.im-float.icon-right .uk-input,
.im-float.icon-right .uk-select { padding-left: 12px; padding-right: 44px; }

/* Icon UIkit định vị chuẩn */
.im-float .uk-form-icon { left: 12px; }
.im-float.icon-right .uk-form-icon { left: auto; right: 12px; }

/* Dark mode */
.uk-dark .im-float-label,
.dark .im-float-label { color: var(--im-label, #aaa); }
.uk-dark .im-float:focus-within .im-float-label,
.dark .im-float:focus-within .im-float-label { color: var(--im-label-active, #ddd); }

/* Trạng thái lỗi/hợp lệ (theo class UIkit nếu bạn dùng uk-form-danger/uk-form-success) */
.im-float .uk-input.uk-form-danger ~ .im-float-label { color: #e5484d; }
.im-float .uk-input.uk-form-success ~ .im-float-label { color: #2ecc71; }

/* Giảm chuyển động nếu người dùng yêu cầu */
@media (prefers-reduced-motion: reduce) {
  .im-float-label { transition: none; }
}

Bước 3: Xử lý autofill và dữ liệu ban đầu

Một số trình duyệt bỏ qua :placeholder-shown khi autofill. Đoạn JS nhỏ sẽ thêm/lấy bớt class .has-value để label luôn đúng vị trí.

// Floating Label helper: xử lý autofill, giá trị ban đầu và sự kiện nhập
(function () {
  function updateState(input) {
    const has = !!input.value;
    if (has) {
      input.classList.add('has-value');          // để chọn bằng selector anh em
      if (input.nextElementSibling && input.nextElementSibling.classList.contains('im-float-label')) {
        // không cần gì thêm; CSS đã dựa vào .has-value + label
      }
    } else {
      input.classList.remove('has-value');
    }
  }

  function initFloat(root = document) {
    const fields = root.querySelectorAll('.im-float .uk-input, .im-float .uk-textarea, .im-float .uk-select');
    fields.forEach((el) => {
      // Khởi tạo trạng thái ban đầu
      updateState(el);

      // Lắng nghe nhập liệu
      el.addEventListener('input', () => updateState(el));
      el.addEventListener('change', () => updateState(el));

      // Trì hoãn kiểm tra autofill sau khi trang tải
      setTimeout(() => updateState(el), 250);
    });
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => initFloat());
  } else {
    initFloat();
  }
})();

Mẹo triển khai

  • Luôn đặt placeholder=" " để kích hoạt :placeholder-shown mà không hiển thị chữ trùng label.
  • Dùng autocomplete đúng chuẩn để tận dụng autofill.
  • Đặt icon bằng .uk-form-icon hoặc .uk-form-icon-flip nếu cần.

Demo trực tiếp

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...