말하자면 슬라이딩 포커스를 쉽게 실현하는 라이브러리

마우스 오버하면 테두리가 자주 이동하는 메뉴를 가끔 보이지만, 이것을 실현하는 라이브러리(또는 하나의 함수)를 만들었습니다. 이런 녀석입니다.

… 조금 프레임 레이트가 낮고 이해하기 어렵기 때문에 움직이는 데모를 참조하십시오.

내가 찾는 방법이 나쁜지, 이 UI를 부르는 방법을 모르기 때문에, 우선 슬라이딩 포커스라고 부르기로 합니다.
영어로는 Sliding Border Navigation Menu라고도 불리는 것 같습니다만, 정확하게는 박스를 이동하고 있는 것, 내비게이션이나 메뉴에 한정할 필요가 없기 때문에, Sliding Focus 입니다.
그리고 이번에 만든 라이브러리의 이름은 Flying Box JS입니다. 혼란 스럽네요.

동작 확인 환경


  • Mac Chrome, Firefox, Safari
  • iPhone 5s Safari
  • Windows Edge

  • 설명



    시소러스


  • 아이템 요소
    메뉴의 항목에 해당합니다.
  • 포커스 요소
    그대로.
  • 홈 요소
    선택 중인 항목 요소. 현재 페이지 등에 해당합니다.
    정확하게는 [data-is-home="true"] 속성이 설정된 아이템 요소입니다.

  • 무엇을 하고 있는가



    기본적으로 다음 두 가지 점입니다.
  • 항목 요소가 마우스 오버되면 포커스 요소의 위치와 크기를 항목 요소에 맞 춥니 다.
  • 클릭 된 항목 요소를 홈 요소로 만듭니다.

    홈 요소와 홈 요소로 이동한 포커스 요소는 기본적으로 [data-is-home="true"]로 설정됩니다.
    나중에 CSS로 잘 장식하십시오.

    최소한의 샘플



    최소한의 데모 의 코드를 게재해 둡니다.
    사용법으로서는 flying-box.js 를 읽어들여, flyingBox() 함수를 실행하면 됩니다.
    GitHub는 이쪽 .
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }
      .flying-box {
        display: flex;
        justify-content: space-between;
        position: relative;
      }
      .flying-box a {
        display: block;
        flex-grow: 1;
        padding: 8px 0;
        text-align: center;
      }
      .flying-box a[data-is-home="true"] {
        color: #f00000;
      }
      .flying-box .flying-box__focus {
        background-color: rgba(0, 128, 240, 0.1);
        pointer-events: none;
        position: absolute;
        transition: all 100ms ease-out;
      }
      .flying-box .flying-box__focus[data-is-home="true"] {
        background-color: rgba(240, 0, 0, 0.1);
      }
    </style>
    <menu class="flying-box">
      <div class="flying-box__focus"></div>
      <a data-is-home="true">Home</a>
      <a>About</a>
      <a>Services</a>
      <a>Help</a>
    </menu>
    <script src="./flying-box.js"></script>
    <script>
      flyingBox()
    </script>
    
    fliying-box.js 는 이렇게 되어 있습니다.
    const flyingBox = (option = {
      itemQuery: '.flying-box a',
      focusQuery: '.flying-box .flying-box__focus',
      homeAttr: 'data-is-home'
    }) => {
      const focus = document.querySelector(option.focusQuery)
      const moveFocus = (item) => {
        if (!item) return
        focus.style['top'] = `${item.offsetTop}px`
        focus.style['left'] = `${item.offsetLeft}px`
        focus.style['width'] = `${item.clientWidth}px`
        focus.style['height'] = `${item.clientHeight}px`
        focus.setAttribute(option.homeAttr, item === queryHome())
      }
      const queryHome = () => document.querySelector(`${option.itemQuery}[${option.homeAttr}=true]`)
      moveFocus(queryHome())
      const items = document.querySelectorAll(option.itemQuery)
      items && items.forEach((item) => {
        item.addEventListener('mouseenter', () => { moveFocus(item) })
        item.addEventListener('mouseleave', () => { moveFocus(queryHome()) })
        item.addEventListener('click', () => {
          const home = queryHome()
          home && home.removeAttribute(option.homeAttr)
          item.setAttribute(option.homeAttr, true)
          focus.setAttribute(option.homeAttr, true)
        })
      })
    }
    

    홈 요소가 동적으로 전환되는 것을 고려한 결과 조금 중복되었습니다.
    터치 디바이스에서는 mouseenter라든지 click를 터치 이벤트로 바꾸는 것이 좋을지도 모릅니다.

    주의점


  • 트랜스파일 되는 전제로 썼습니다.
  • 「마우스 오버에서는 슬라이드 하지 않고, 클릭했을 때만 슬라이드 한다」와 같은 거동의 구현은… 맡깁니다.
  • 이 슬라이딩 포커스, 실은 CSS만으로도 구현할 수 있습니다만, 「각 아이템의 사이즈를 결정 치지 않으면 안 된다」 「라디오 버튼등을 사용하지 않으면 클릭으로 고정할 수 없다」등의 고행이 기다려 있기 때문에 추천 할 수 없습니다. CSS만으로 어떻게든 하려고 하는 것은 그만두자.

  • 결론



    UI 의 이름을 모르는 문제, 어떻게 하고 싶다.

    좋은 웹페이지 즐겨찾기