垂直にスクロールするときに水平スクロールを許可しない(およびその逆)


17

overflow-xとにoverflow-y設定したリストがありますauto。さらに、モメンタムスクロールを設定したので、を使用してタッチスクロールがモバイルでうまく機能しwebkit-overflow-scrolling: trueます。

ただし、問題は、垂直にスクロールするときに水平スクロールを無効にする方法がわからないことです。左上または右上にスワイプするとテーブルが斜めにスクロールするため、ユーザーエクスペリエンスが非常に低下します。ユーザーが垂直方向にスクロールしているときは、ユーザーが垂直方向のスクロールを停止するまで、水平方向のスクロールは絶対にしたくない。

私は以下を試しました:

JS:

offsetX: number;
offsetY: number;
isScrollingHorizontally = false;
isScrollingVertically = false;

//Detect the scrolling events
ngOnInit() {
    this.scrollListener = this.renderer.listen(
      this.taskRows.nativeElement,
      'scroll',
      evt => {
        this.didScroll();
      }
    );

    fromEvent(this.taskRows.nativeElement, 'scroll')
      .pipe(
        debounceTime(100),
        takeUntil(this.destroy$)
      )
      .subscribe(() => {
        this.endScroll();
    });
}

didScroll() {
    if ((this.taskRows.nativeElement.scrollLeft != this.offsetX) && (!this.isScrollingHorizontally)){
        console.log("Scrolling horizontally")
        this.isScrollingHorizontally = true;
        this.isScrollingVertically = false;
        this.changeDetectorRef.markForCheck();
    }else if ((this.taskRows.nativeElement.scrollTop != this.offsetY) && (!this.isScrollingVertically)) {
        console.log("Scrolling Vertically")
        this.isScrollingHorizontally = false;
        this.isScrollingVertically = true;
        this.changeDetectorRef.markForCheck();
    }
}

endScroll() {
    console.log("Ended scroll")
    this.isScrollingVertically = false;
    this.isScrollingHorizontally = false;
    this.changeDetectorRef.markForCheck();
}

HTML:

<div
    class="cu-dashboard-table__scroll"
    [class.cu-dashboard-table__scroll_disable-x]="isScrollingVertically"
    [class.cu-dashboard-table__scroll_disable-y]="isScrollingHorizontally"
>

CSS:

&__scroll {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: auto;
  will-change: transform;
  -webkit-overflow-scrolling: touch;

  &_disable-x {
     overflow-x: hidden;
  }

  &_disable-y {
    overflow-y: hidden;
  }
}

しかし、毎回のIセットoverflow-xまたはoverflow-yhiddenそのグリッチとトップに戻ってジャンプし、スクロール、スクロールされたとき。私もそれに気づきましたwebkit-overflow-scrolling: trueこれが発生する理由に削除すると動作が停止したように見えますが、モバイルデバイスでの勢いのあるスクロールには絶対に必要です。

垂直にスクロールするときに水平スクロールを無効にするにはどうすればよいですか?


スクロールの問題を解決する方法がわかりません。たぶん、一歩戻って、2つの軸のいずれかがスクロールしないようにしてみてください。トピック外:テーブルは、実際には小さな画面用ではありません。
Joep Kockelkorn

コードに中括弧がありません。スニペットとして追加すると、コンソールにエラーメッセージが表示されます。
Razvan Zamfir、

ただ愚かな考え。スクロールに2つのスライダーまたはカスタムスライダーを使用しないのはなぜですか?
Thomas Ludewig

回答:


4

これを試して

HTML
<div
  class="cu-dashboard-table__scroll-vertical"
>
  <div
    class="cu-dashboard-table__scroll-horizontal"
  >
    <!-- Scroll content here -->
  </div>
</div>


CSS
&__scroll {
  &-horizontal {
    overflow-x: auto;
    width: 100%;
    -webkit-overflow-scrolling: touch;
  }

  &-vertical {
    overflow-y: auto;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
}

スクロールに1つのdivを使用する代わりに、2つを使用しないのはなぜですか?XとYに1つずつ


1
いい案!病気でこれを試してみてください。
Josh O'Connor

1
笑、これは独創的なアイデアだと言わざるを得ません。
frodo2975

15

データの大きなテーブルを表示している場合を除いて、モバイルで多軸スクロールを必要とすることは、デザインにとって一般的に悪い習慣です。とはいえ、なぜそれを防ぎたいのですか?ユーザーが斜めにスクロールしたいのなら、それは世界の終わりのようには思えません。OSX上のChromeのような一部のブラウザーは、デフォルトですでに説明していることを実行しています。

単軸スクロールが必要な場合、考えられる解決策は、touchstarttouchmoveイベントを介して自分でスクロール位置を追跡することです。ドラッグのしきい値をブラウザーのしきい値よりも低く設定すると、スクロールが始まる前にcssを実行できるようになり、グリッチが認識されないようにすることができます。また、まだグリッチが発生している場合でも、タッチの開始位置と現在の位置がわかります。これらから、divの開始スクロール位置を記録すると、手動でdivを正しい場所にスクロールして、必要に応じて先頭にジャンプするのを防ぐことができます。可能なアルゴリズムは次のようになります。

// Touchstart handler
if (scrollState === ScrollState.Default) {
    // Record position and id of touch
    touchStart = touch.location
    touchStartId = touch.id.
    scrollState = ScrollState.Touching

    // If you have to manually scroll the div, first store its starting scroll position:
    containerTop = $('.myContainer').scrollTop();
    containerLeft = $('.myContainer').scrollLeft();
}

// Touchmove handler - If the user has dragged beyond a distance threshold,
// do the css classes swap.
if (touch.id === touchStartId && distance(touchStart, touch.location > threshold) {
    scrollState = ScrollState.Scrolling;
    swapCssClasses();

    // If you have to manually scroll the div to prevent jump:
    $('.myContainer').scrollTop(containerTop + (touch.location.y - touchStart.y));
    // Do the same for horizontal scroll.
}

// Then, listen for debounced scroll events, like you're already doing,
// to reset your state back to default.

2番目のアイデア:cssクラスを変更する代わりに、スクロールハンドラーで、ロックする軸のdivのスクロール位置を直接設定します。IE、水平方向にスクロールしている場合は、常にscrollTopをその開始値に設定します。確かに、これによってスクロールがキャンセルされることもあります。それが機能するかどうかを確認するために、それを試す必要があります。


私はこれを試してみましたが、とてもびくびくしてパフォーマンスはひどいものでした。
Josh O'Connor

3

これを解決しようとする多くの方法があります。いくつかの良いアイデアがここに提供されています。

ただし、他の人が言及したように、多次元スクロールに依存する(または回避しようとする)ことはUXの悪臭であり、UXが問題であることを示しています。これは正当な開発者の問題ではないと思います。一歩下がって、達成しようとしていることを再評価することをお勧めします。問題の1つは、UIをより使いやすくするためにユーザーを混乱させることです。ここで説明する操作性は混乱を招く可能性があります。

水平にスクロールできないのはなぜですか?

垂直方向のスクロールを停止すると、水平方向にしかスクロールできないのはなぜですか?

これらは、聞こえるかもしれないいくつかの質問です(聞き取れません)。

ユーザーが行を選択したときにのみ、垂直データリストの追加情報を参照可能にしようとする場合、デフォルトでは、垂直方向にのみスクロール可能で、垂直方向のみを切り替えてフラットリストを作成する方がはるかに優れています。 「行」が選択/アクティブ化されたときの情報。詳細を折りたたむと、フラットな垂直リストに戻ります。

このような周辺の技術的な課題を解決するためにフープを飛び越えなければならない場合は、ユーザーエクスペリエンスがそもそもうまく設計されていないことを示しています。


3

3つのコンテナーを使用する必要があります。
最初のコンテナーでは、垂直スクロールを有効にし、水平スクロールを禁止します。
2番目では、その逆で、水平スクロールを有効にし、垂直スクロールを無効にします。とを必ず使用してください。そうしないoverflow-x: hidden;overflow-y: hidden;、子コンテナが現在のコンテナを超える可能性があります。
また、使用する必要がありますmin-width: 100%; min-height: 100%;
3番目のコンテナーには、使用する必要がありますdisplay: inline-block;、内部コンテンツがこのコンテナーを拡大し、対応するスクロールバーが2つの親ブロックに表示されます。

HTML

<div class="scroll-y">
  <div class="scroll-x">
    <div class="content-container">

      <!-- scrollable content here -->

    </div>
  </div>
</div>

CSS

.scroll-y {
  position: absolute;
  overflow-x: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
}

.scroll-x {
  overflow-y: hidden;
  overflow-x: auto;
  width: auto;
  min-width: 100%;
  min-height: 100%;
}

.content-container {
  min-width: 100%;
  min-height: 100%;
  display: inline-block;
}

ここでテストできます iPhoneのSafariで。

幸運を!!😉


:raised hands::raised hands:
cup_of '11 / 10/11

0

これは楽しいようです;)

それが妥当であるかどうかについては議論しません。

私はRxJSでそれを試しました:

  ngAfterViewInit() {
    const table = document.getElementById("table");

    const touchstart$ = fromEvent(table, "touchstart");
    const touchmove$ = fromEvent(table, "touchmove");
    const touchend$ = fromEvent(table, "touchend");

    touchstart$
      .pipe(
        switchMapTo(
          touchmove$.pipe(
            // tap(console.log),
            map((e: TouchEvent) => ({
              x: e.touches[0].clientX,
              y: e.touches[0].clientY
            })),
            bufferCount(4),
            map(calculateDirection),
            tap(direction => this.setScrollingStyles(direction)),
            takeUntil(touchend$)
          )
        )
      )
      .subscribe();
  }

私たちは、すべての第四バッファtouchemoveイベントをして、4つのイベントの座標(といくつかの非常に洗練された計算にするmap(calculateDirection))出力RIGHTLEFTUPまたはをDOWNと私は無効に垂直またはhoricontalスクロールしようということに基づきます。私のアンドロイド携帯電話ではクロムのように動作します;)

小さな遊び場を作りました

乾杯クリス

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.