✦ Verified product
Puffly トラベルポーチ|大容量×ワイドオープン/防水ポケット付き
JPY 3,980.00
Urban Desk
Verified independent store
→
.description_text h2 { text-align: center; font-weight: bold; } .description_text h1 { font-size: 22px; font-weight: 700; text-align: center; } .product_description_wrapper { margi
n-bottom: 4rem; } たっぷり入る!驚きの収納力 複数のポケットと広い収納スペースで、化粧品や洗面用具などをすっきり整理。必要なアイテムがひと目で見つかります。 ブラシや小物の収納に便利な前面ポケット 2つのポケットでメイクブラシや歯ブラシ、トラベル小物をすっきり整理。軽くて拭き取りやすいPVC素材で、汚れてもサッとお手入れできます。 使いやすさ抜群のワイドオープン設計 大きく開いて中が見やすく、取り出しもスムーズ。ボトルを立てて固定できるゴムバンド付きで、移動中も中身が崩れにくい設計です。 濡れたものも安心の防水ポケット 背面にPVC素材のポケットを配置。濡れたタオルや水回りのアイテムも、他の荷物と分けて清潔に収納できます。 持ち運びにも便利な工夫がたっぷり 左右どちらからでも開けられるダブルジッパーと、サッと持ち上げられるトップハンドル付き。旅先やジムでも使いやすさを追求しました。 const image_comparison_slider_template = document.createElement('template'); image_comparison_slider_template.innerHTML = ` :host { display: inline-block; position: relative; width: 100%; max-width: 600px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); cursor: ew-resize; overflow: hidden; } .slider-container { position: relative; width: 100%; height: 100%; } img { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; } .image-after { position: relative; z-index: 1; } .image-before-wrapper { position: absolute; top: 0; left: 0; width: 50%; height: 100%; overflow: hidden; z-index: 2; } .image-before { position: absolute; top: 0; left: 0; height: 100%; max-width: none; } .slider-handle { position: absolute; top: 0; left: 50%; width: 4px; height: 100%; background-color: white; transform: translateX(-50%); z-index: 3; pointer-events: none; } .slider-circle { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 50px; height: 50px; background-color: rgba(255, 255, 255, 0.9); border-radius: 50%; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); display: flex; justify-content: space-evenly; align-items: center; } .arrow { border-style: solid; border-color: transparent; } .arrow.left { border-width: 8px 12px 8px 0; border-right-color: #333; } .arrow.right { border-width: 8px 0 8px 12px; border-left-color: #333; } .label { position: absolute; top: 10px; padding: 5px 10px; background-color: rgba(0, 0, 0, 0.7); color: white; font-family: sans-serif; font-size: 14px; font-weight: bold; border-radius: 4px; pointer-events: none; z-index: 4; } .label-before { left: 10px; } .label-after { right: 10px; } Before After `; class ImageComparisonSlider extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild(image_comparison_slider_template.content.cloneNode(true)); this.beforeWrapper = this.shadowRoot.querySelector('#image-before-wrapper'); this.sliderHandle = this.shadowRoot.querySelector('#slider-handle'); this.beforeImage = this.shadowRoot.querySelector('#image-before'); this.afterImage = this.shadowRoot.querySelector('#image-after'); this.beforeLabel = this.shadowRoot.querySelector('#label-before'); this.afterLabel = this.shadowRoot.querySelector('#label-after'); this.isDragging = false; this._boundMoveSlider = this.moveSlider.bind(this); this._boundStartDragging = this.startDragging.bind(this); this._boundStopDragging = this.stopDragging.bind(this); } static get observedAttributes() { return ['before-src', 'after-src', 'before-label', 'after-label']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) return; switch (name) { case 'before-src': this.beforeImage.src = newValue; break; case 'after-src': this.afterImage.src = newValue; break; case 'before-label': this.beforeLabel.textContent = newValue; break; case 'after-label': this.afterLabel.textContent = newValue; break; } } connectedCallback() { this.addEventListener('mousedown', this._boundStartDragging); this.addEventListener('touchstart', this._boundStartDragging, { passive: false }); window.addEventListener('mousemove', this._boundMoveSlider); window.addEventListener('touchmove', this._boundMoveSlider); window.addEventListener('mouseup', this._boundStopDragging); window.addEventListener('touchend', this._boundStopDragging); this.resizeObserver = new ResizeObserver(() => this.setBeforeImageSize()); this.resizeObserver.observe(this); } disconnectedCallback() { this.removeEventListener('mousedown', this._boundStartDragging); this.removeEventListener('touchstart', this._boundStartDragging); window.removeEventListener('mousemove', this._boundMoveSlider); window.removeEventListener('touchmove', this._boundMoveSlider); window.removeEventListener('mouseup', this._boundStopDragging); window.removeEventListener('touchend', this._boundStopDragging); this.resizeObserver.disconnect(); } setBeforeImageSize() { const containerWidth = this.offsetWidth; this.beforeImage.style.width = `${containerWidth}px`; } startDragging(e) { this.isDragging = true; e.preventDefault(); } stopDragging() { this.isDragging = false; } moveSlider(e) { if (!this.isDragging) return; const rect = this.getBoundingClientRect(); const x = (e.clientX || e.touches[0].clientX) - rect.left; const position = Math.max(0, Math.min(x, rect.width)); const percentage = (position / rect.width) * 100; this.beforeWrapper.style.width = `${percentage}%`; this.sliderHandle.style.left = `${percentage}%`; } } customElements.define('image-comparison-slider', ImageComparisonSlider);