js+css实现自定义风格的下拉选择框效果代码
代码语言:html
所属分类:表单美化
代码描述:js+css实现自定义风格的下拉选择框效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=DM+Sans&display=swap'> <style> @charset "UTF-8"; * { border: 0; box-sizing: border-box; margin: 0; padding: 0; } :root { --hue: 223; --bg: hsl(0,0%,100%); --fg: hsl(var(--hue),10%,10%); --trans-dur: 0.3s; --trans-ease-in-out: cubic-bezier(0.65,0,0.35,1); --trans-ease-out: cubic-bezier(0.33,1,0.68,1); font-size: calc(20px + (40 - 20) * (100vw - 280px) / (3840 - 280)); } body, button { color: var(--fg); font: 1em/1.5 "DM Sans", sans-serif; transition: background-color var(--trans-dur), color var(--trans-dur); } body { background-color: var(--bg); display: flex; height: 100vh; } main { margin: auto; padding: 0.75em 0; width: min-content; height: 12em; } .drop { --drop-trans-dur: 0.5s; --drop-flare-dist: 0; border-radius: 0.5em; margin: auto; padding: 0.25em 0.25em 0 0.25em; position: relative; min-width: 9em; } .drop, .drop:after { background-color: hsl(var(--hue), 10%, 90%); transition: background-color var(--trans-dur); } .drop:before, .drop:after { content: ""; position: absolute; } .drop:before { background-image: radial-gradient(100% 100% at 100% 50%, hsla(var(--hue), 90%, 50%, 0.5), hsla(var(--hue), 90%, 50%, 0) 50%); display: none; right: 0; bottom: 100%; width: 9em; height: 9em; } .drop:after { border-radius: 0.4375em; display: block; top: 0.125em; left: 0.125em; width: calc(100% - 0.25em); height: calc(100% - 0.25em); } .drop__btn { background-color: white; border-radius: 0.375em; box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 0); cursor: pointer; display: flex; align-items: center; line-height: 1; height: 2.5em; outline: transparent; margin-bottom: 0.25em; padding: 0.75em; position: relative; width: 100%; transition: background-color var(--trans-dur), box-shadow calc(var(--trans-dur) / 2) var(--trans-ease-in-out), color var(--drop-trans-dur); -webkit-appearance: none; appearance: none; -webkit-tap-highlight-color: transparent; z-index: 1; } .drop__btn:hover, .drop__btn:focus-visible, .drop__btn[aria-expanded=true] { background-color: hsl(var(--hue), 10%, 95%); } .drop__btn:focus-visible { box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 1); } .drop__btn:after { border-top: 0.375em solid currentColor; border-right: 0.375em solid transparent; border-left: 0.375em solid transparent; content: ""; display: block; margin-inline-start: auto; width: 0; height: 0; transform-origin: 50% 37.5%; transition: transform var(--drop-trans-dur) var(--trans-ease-out); } .drop__btn[aria-expanded=true]:after { transform: rotate(0.5turn); } .drop--collapsing, .drop--expanding, .drop__items { overflow: hidden; } .drop__items { height: 0; } .drop__items-inner { visibility: hidden; } .drop--collapsing .drop__btn[aria-expanded=true] { background-color: white; } .drop--collapsing .drop__btn[aria-expanded=true]:after { transform: rotate(0); } .drop--expanding:before { display: block; } .drop__items .drop__btn:hover, .drop__items .drop__btn:focus-visible { background-color: hsl(var(--hue), 10%, 97.5%); color: hsla(var(--hue), 90%, 50%); } .drop__items .drop__btn:focus-visible { box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 0); } .drop__items .drop__btn:after { border: 0; content: "✓"; display: none; width: auto; height: auto; } .drop__items .drop__btn--selected:after { display: block; } .drop__btn[aria-expanded=true] ~ .drop__items { height: auto; } .drop__btn[aria-expanded=true] ~ .drop__items .drop__items-inner { visibility: visible; } .drop:has([aria-expanded=true]) { height: auto; } .drop:has([aria-expanded=true]):before { transform: translateY(calc(9em + var(--drop-flare-dist))); transition: transform var(--drop-trans-dur) linear; } /* Dark theme */ @media (prefers-color-scheme: dark) { :root { --bg: hsl(var(--hue),10%,10%); --fg: hsl(var(--hue),10%,90%); } .drop, .drop:after { background-color: black; } .drop__btn { background-color: hsl(var(--hue), 10%, 10%); } .drop__btn:hover, .drop__btn:focus-visible, .drop__btn[aria-expanded=true] { background-color: hsl(var(--hue), 10%, 20%); } .drop__items .drop__btn:hover, .drop__items .drop__btn:focus-visible { background-color: hsl(var(--hue), 10%, 15%); color: hsla(var(--hue), 90%, 70%); } .drop--collapsing .drop__btn[aria-expanded=true] { background-color: hsl(var(--hue), 10%, 10%); } } </style> </head> <body> <main> <div class="drop" id="dummy"> <button class="drop__btn" aria-expanded="false" aria-haspopup="true" type="button"></button> <div class="drop__items" data-items> <div class="drop__items-inner"> <button class="drop__btn" type="button" value="windows">Windows</button> <button class="drop__btn" type="button" value="mac">Mac</button> <button class="drop__btn" type="button" value="linux">Linux</button> </div> </div> </div> </main> <script > "use strict"; window.addEventListener("DOMContentLoaded", () => { const drop = new DropdownMenu("#dummy"); }); class DropdownMenu { /** * @param el CSS selector of the menu */ constructor(el) { var _a, _b, _c; /** Animation objects */ this.animations = []; /** Options for this menu */ this.options = [ { name: "windows", friendlyName: "Windows" }, { name: "mac", friendlyName: "Mac" }, { name: "linux", friendlyName: "Linux" } ]; /** Selected option by name */ this.selected = "windows"; /** Menu is collapsing */ this.isCollapsing = false; /** Menu is expanding */ this.isExpanding = false; /** Actions to run after collapsing the item. */ this.animActionsCollapse = { onfinish: this.onAnimationFinish.bind(this, false), oncancel: () => { this.isCollapsing = false; } }; /** Actions to run after expanding the item. */ this.animActionsExpand = { onfinish: this.onAnimationFinish.bind(this, true), oncancel: () => { this.isExpanding = false; } }; this.el = document.querySelector(el); this.menuButton = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector("button"); this.itemList = (_b = this.el) === null || _b === void 0 ? void 0 : _b.querySelector("[data-items]"); this.defaultOption(); document.addEventListener("click", this.outsideToClose.bind(this)); window.addEventListener("keydown", this.escToClose.bind(this)); (_c = this.el) === null || _c === void 0 ? void 0 : _c.addEventListener("click", this.toggle.bind(this)); window.addEventListener("keydown", this.kbdAction.bind(this)); } /** Transition duration specific to the menu */ get transDuration() { if (this.el) { const style = getComputedStyle(this.el); const rawDur = style.getPropertyValue("--drop-trans-dur"); let dur = rawDur.substring(0, rawDur.indexOf("s")); const mIndex = dur.indexOf("m"); if (mIndex > -1) { dur = dur.substring(0, mIndex); return +dur; } // seconds to milliseconds return +dur * 1e3; } return 0; } /** Display the default selected option. */ defaultOption() { var _a; const buttonEl = (_a = this.itemList) === null || _a === void 0 ? void 0 : _a.querySelector(`[value="${this.selected}"]`); buttonEl === null || buttonEl === void 0 ? void 0 : buttonEl.classList.add("drop__btn--selected"); if (this.menuButton) { const optionFound = this.options.find(option => option.name === this.selected); this.menuButton.textContent = (optionFound === null || optionFound === void 0 ? void 0 : optionFound.friendlyName) || ""; } } /** * Navigate the menu options with arrow keys. * @param e Keydown event */ kbdAction(e) { var _a; const { key } = e; const tabOrArrow = key === "Tab" || key === "ArrowUp" || key === "ArrowDown"; const notAnimating = !this.isExpanding && !this.isCollapsing; i.........完整代码请登录后点击上方下载按钮下载查看
网友评论0