Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> CSS

จัดสไตล์ปุ่มอัปโหลดไฟล์ ด้วย CSS ::file-selector-button Selector

CSS Pseudo-element ::file-selector-button (และ ::-webkit-file-upload-button) ใช้จัดสไตล์ปุ่ม "Browse/Choose File" ของ <input type="file"> ได้โดยตรง ไม่ต้องใช้ Hack ซ่อน Input แล้วสร้างปุ่มแทน

Syntax

selector::file-selector-button {
  /* Standard (Firefox) */
  property: value;
}
selector::-webkit-file-upload-button {
  /* WebKit/Blink (Chrome, Safari, Edge) */
  property: value;
}

Browser Support

BrowserSelectorSupport
Firefox::file-selector-buttonFull ✅
Chrome 89+::-webkit-file-upload-buttonFull ✅
Safari 15.4+::-webkit-file-upload-buttonFull ✅
Edge 89+::-webkit-file-upload-buttonFull ✅
Safari < 15.4-ไม่รองรับ ❌

ตัวอย่างที่ 1: Firefox - Hover Effect

<!DOCTYPE html>
<html>
<head>
  <style>
    input[type=file]::file-selector-button:hover {
      cursor: grab;
      background-color: blueviolet;
      color: white;
      font-size: 1.2em;
      box-shadow: inset 5px 10px 10px cornflowerblue;
    }
  </style>
</head>
<body>
  <form>
    <label for="fup">Click to</label>
    <input type="file" id="fup" />
    <input type="text" placeholder="Random Text here" />
    <button type="submit">Done</button>
  </form>
</body>
</html>

ตัวอย่างที่ 2: Cross-browser (Chrome + Firefox)

<!DOCTYPE html>
<html>
<head>
  <style>
    input[type=file]::file-selector-button:hover,
    input[type=file]::-webkit-file-upload-button:hover {
      cursor: pointer;
      background-color: crimson;
      font-size: 1.2em;
      border-radius: 25%;
      box-shadow: inset 5px 10px 10px cornsilk;
    }
  </style>
</head>
<body>
  <form>
    <label for="fup">Click to</label>
    <input type="file" id="fup" />
    <input type="text" placeholder="using webkit prefix" />
    <button type="submit">Done</button>
  </form>
</body>
</html>

Complete Custom File Input Style

.file-input-wrapper {
  position: relative;
  display: inline-block;
  width: 100%;
  max-width: 400px;
}

.file-input-wrapper input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}

.file-input-wrapper .file-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  background: #4285f4;
  color: white;
  border-radius: 6px;
  font-size: 1rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s, box-shadow 0.2s;
  border: none;
  white-space: nowrap;
}

.file-input-wrapper .file-button:hover {
  background: #3367d6;
  box-shadow: 0 2px 8px rgba(66,133,244,0.3);
}

.file-input-wrapper .file-button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(66,133,244,0.4);
}

.file-input-wrapper .file-name {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: #666;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Native Button Styling (Progressive Enhancement) */
.file-input-wrapper input[type="file"]::file-selector-button,
.file-input-wrapper input[type="file"]::-webkit-file-upload-button {
  margin-right: 0.5rem;
  padding: 0.5rem 1rem;
  background: #4285f4;
  color: white;
  border: none;
  border-radius: 4px;
  font: inherit;
  cursor: pointer;
  transition: background 0.2s;
}

.file-input-wrapper input[type="file"]::file-selector-button:hover,
.file-input-wrapper input[type="file"]::-webkit-file-upload-button:hover {
  background: #3367d6;
}

HTML Structure

<div class="file-input-wrapper">
  <input type="file" id="avatar" accept="image/*" aria-describedby="avatar-hint">
  <button type="button" class="file-button" tabindex="-1">
    <svg aria-hidden="true" width="20" height="20">...upload icon...</svg>
    Choose File
  </button>
  <div class="file-name" id="avatar-hint">No file chosen</div>
</div>

Styling คุณสมบัติเพิ่มเติม

Multiple Files

input[type="file"][multiple]::file-selector-button::after {
  content: " (Multiple)";
  font-size: 0.8em;
}

Accept Attribute Styling

input[type="file"][accept*="image"]::file-selector-button::before {
  content: "🖼️ ";
}
input[type="file"][accept*="pdf"]::file-selector-button::before {
  content: "📄 ";
}

Disabled State

input[type="file"]:disabled::file-selector-button,
input[type="file"]:disabled::-webkit-file-upload-button {
  opacity: 0.5;
  cursor: not-allowed;
  background: #ccc;
}

Fallback สำหรับ Safari เก่า / Browser ไม่รองรับ

/* Hide native button completely */
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
  display: none;
}

/* Custom Button Overlay (Label Trick) */
.file-input-label {
  display: inline-block;
  cursor: pointer;
}
.file-input-label input[type="file"] {
  position: absolute;
  opacity: 0;
  width: 0.1px;
  height: 0.1px;
}
.file-input-label .custom-button {
  /* Styles here */
}

/* JS Fallback Detection */
if (!CSS.supports('selector(::file-selector-button)') && 
    !CSS.supports('selector(::-webkit-file-upload-button)')) {
  document.body.classList.add('no-file-selector-support');
}

Accessibility

  • ใช้ <label> ผูกกับ Input (Implicit หรือ Explicit)
  • accept attribute ระบุประเภทไฟล์ที่ยอมรับ
  • aria-describedby ชี้ไปยัง Element แสดงชื่อไฟล์
  • Custom Button ต้องมี tabindex="-1" (ไม่รับ Focus เอง Input จะรับ)
  • Focus Indicator ต้องชัดเจนบน Input (ซ่อนอยู่) หรือ Label