質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

4363閲覧

tailwindcss(headlessui)でModal表示するとfixedの中の中央揃え要素が右にずれる

maztak

総合スコア61

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/09/04 07:02

編集2021/09/05 09:09

React x tailwindcssをベースにしたUIコンポーネントであるheadlessUIのDialog(Modal)コンポーネントを使って開発しています。Modalが開くと背景のスクロールを防ぐためにhtmlタグにoverflow: hidden; padding-right: 15px;が付与されます(padding-rightは消えたスクロールバーのズレを防ぐため)。

しかしfixedで上部固定しているヘッダーが中央揃え(mx-auto)のため、このpadding-rightにより中央位置がずれ、中の要素が右にずれます。
イメージ説明

margin-leftを固定値にしてしまえば影響をうけないのですが、なるべく画面幅によらず綺麗に中央揃えにしたく。。良い解決方法はありませんでしょうか‥?

コード

tsx

1// Layout.tsx 2import { Popover, Transition } from '@headlessui/react'; 3import { InformationCircleIcon, MenuIcon, XIcon } from '@heroicons/react/outline'; 4import Image from 'next/image'; 5import Link from 'next/link'; 6import { Fragment, useState } from 'react'; 7 8export default function Layout() => { 9 const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); 10 11 function openLoginModal() { 12 setIsLoginModalOpen(true) 13 } 14 15 return ( 16 <Popover className='fixed left-0 right-0 bg-white z-10'> <!-- ここがfiexdでwindow基準なので --> 17 <div className='mx-auto max-w-7xl px-2 lg:px-4'> <!-- このmx-autoによる中心位置がずれる --> 18 <div className='flex flex-col lg:flex-row lg:justify-end lg:items-center lg:h-24 lg:space-x-10'> 19 <div className="flex justify-end lg:justify-start items-center h-14"> 20 <div className='flex flex-grow'> 21 <Link href='/' passHref> 22 <a className='flex items-center'> 23 <Image 24 className='w-auto h-8 sm:h-10 cursor-pointer' 25 src={logo} 26 alt='' 27 width='164' 28 height='48' 29 /> 30 </a> 31 </Link> 32 </div> 33 </div> 34 35 <div className="flex flex-row items-center justify-end space-x-10"> 36 <Popover.Group as='nav' className='hidden lg:flex space-x-10'> 37 <a 38 href='https://example.com/about' 39 className='text-base font-medium text-gray-500 hover:text-gray-900' 40 > 41 About 42 </a> 43 </Popover.Group> 44 45 <div className='hidden lg:flex lg:flex-1 items-center'> 46 <LoginModal isOpen={isLoginModalOpen} setIsOpen={setIsLoginModalOpen}> 47 <button 48 className='mx-auto justify-center py-2 px-4 text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 rounded-md border border-transparent' 49 onClick={openLoginModal} 50 > 51 Sign in with Twitter 52 </button> 53 </LoginModal> 54 </div> 55 </div> 56 </div> 57 </div> 58 </Popover> 59 ) 60 }

LoginModal.tsxの中身はほぼそのままで、htmlにoverflow, padding-rightが付与されるのはheadlessuiの仕様です。

tsx

1// LoginModal.tsx 2import { Dialog, Transition } from '@headlessui/react' 3import { Fragment } from 'react' 4import TwitterSigninButton from './TwitterSigninButton' 5 6export default function LoginModal({ isOpen, setIsOpen, children }) { 7 8 return ( 9 <> 10 {children} 11 <Transition.Root show={isOpen} as={Fragment}> 12 <Dialog 13 as="div" 14 auto-reopen="true" 15 className="fixed z-50 inset-0 overflow-y-auto" 16 onClose={setIsOpen} 17 > 18 <div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> 19 <Transition.Child 20 as={Fragment} 21 enter="ease-out duration-300" 22 enterFrom="opacity-0" 23 enterTo="opacity-100" 24 leave="ease-in duration-200" 25 leaveFrom="opacity-100" 26 leaveTo="opacity-0" 27 > 28 <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> 29 </Transition.Child> 30 31 {/* This element is to trick the browser into centering the modal contents. */} 32 <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"> 33 &#8203; 34 </span> 35 <Transition.Child 36 as={Fragment} 37 enter="ease-out duration-300" 38 enterFrom="opacity-0 scale-95" 39 enterTo="opacity-100 scale-100" 40 leave="ease-in duration-200" 41 leaveFrom="opacity-100 scale-100" 42 leaveTo="opacity-0 scale-95" 43 > 44 <div className="inline-block w-full max-w-md p-6 my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-xl rounded-2xl"> 45 <Dialog.Title 46 as="h3" 47 className="text-lg font-medium leading-6 text-gray-900 mb-3" 48 > 49 アカウント登録・ログイン 50 </Dialog.Title> 51 <div className="mt-2"> 52 <p className="text-sm text-gray-500 mb-4"> 53 アカウント登録、もしくはログインすると<a href="https://example.com/terms" target="_blank" rel="noreferrer" className="text-blue-400">利用規約</a><a href="https://example.com/privacy" target="_blank" rel="noreferrer" className="text-blue-400">プライバシーポリシー</a>に同意したものとみなされます。 54 </p> 55 <TwitterSigninButton /> 56 </div> 57 </div> 58 </Transition.Child> 59 </div> 60 </Dialog> 61 </Transition.Root> 62 </> 63 ) 64}

環境

"next": "11.0.1", "react": "17.0.2", "@headlessui/react": "^1.4.0", "tailwindcss": "^2.2.7",

試したこと

###htmlにoverflow: scroll; !importantを追加
常にスクロールバーを表示する方法ですが、fixed部分は確かに解消するものの、Modalの背面スクロールが可能になってしまうので本末転倒なのと、今度は今まで大丈夫だったfixed以外の要素がpadding-right: 15px;により左にずれます。

isLoginModalOpenによりcssクラスを出し分け

css

1.scrollbar-padding { 2 padding-right: 15px; 3}

tsx

1 <Popover className={isLoginModalOpen 2 ? 'fixed left-0 right-0 bg-white z-10 scrollbar-padding' 3 : 'fixed left-0 right-0 bg-white z-10'}>

このようにしてModalが出た時だけfixed要素に独自クラスを追加する方法。うまくいく場合はある(fixedの中の要素が微動だにしない)ものの、基本的にはスクロールバーの表示やhtmlへのpadding-right付与のタイミングとずれてより左右にガクガクなります。

isScrollbarShownステートを使って判定

上記を応用してスクロールバーの有無を判定してやろうと思いましたが、下記のコードでは常にfalseになり上手く行かず、、また中央揃えのためにわざわざ不安定なstateを増やすのもナンセンスと思い途中でやめました。。

tsx

1const [isScrollbarShown, setIsScrollbarShown] = useState(null); 2 3useEffect(() => { 4 if( window.innerHeight >= document.documentElement.clientHeight ){ 5 //スクロールバー無し 6 setIsScrollbarShown(false); 7 } else { 8 setIsScrollbarShown(true); 9}, [isLoginModal])

調べたこと

headlessui github issue
https://github.com/tailwindlabs/headlessui/search?q=padding-right&type=issues
解決策はありませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

htmlのスクロールバーを表示しない設定にすることで防ぎました。UX的にベストとは言えないですが。

Next.jsで<html>タグにクラスを当てるには_document.jsを用意します。
https://nextjs.org/docs/advanced-features/custom-document

またtailwindcssにはtailwind-scrollbar-hideライブラリがありますので、これを入れて_document.jsで<Html className='scrollbar-hide'>としてやるだけです。
https://www.npmjs.com/package/tailwind-scrollbar-hide

注意点として、_document.jsを追加したら一度サーバーを再起動しないと反映されません。

投稿2021/09/11 08:12

maztak

総合スコア61

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問