Safari 8多次选择滚动问题

时间:2022-08-24 11:09:22

I have been encountering an issue when using multiple select select fields within Safari 8 on OS X Yosemite. If the select field has an applied width, either in-line or as a class, I am unable to use the keyboards arrow keys to scroll down through the select as per normal behaviour.

在OS X Yosemite上使用Safari 8中的多个select字段时,我遇到了一个问题。如果选择字段具有应用的宽度,无论是在线的还是作为类的,我都不能使用键盘箭头键来按正常行为向下滚动。

<select size="5" name="selectMultiple" multiple="multiple">

Multiple select JSFiddle.

多个选择JSFiddle。

<select size="5" name="selectMultiple" multiple="multiple" style="width:100%;">

with style tag JSFiddle.

与JSFiddle风格标记。

When the select has style the selection moves out of view instead of scrolling the list downwards keeping the selected item in view.

当select具有样式时,选择将移出视图,而不是向下滚动列表,使选中的项保持在视图中。

Is this a bug in the version of Safari (Version 8.0 (10600.1.25)) I am using. I am using BrowserStack for my testing. Or is this something I can address with a fix through my code?

这是我正在使用的Safari版本(8.0版本(10600.1.25)中的一个bug吗?我正在使用BrowserStack进行测试。或者我可以通过我的代码来解决这个问题?

Thank you.

谢谢你!

1 个解决方案

#1


1  

I think this is indeed some type of bug that has to do with the width of the select element vs the scrollHeight of the element.

我认为这确实是某种与select元素的宽度和元素的滚动高度有关的bug。

The more options you have, the wider it can be and still work fine. If I have a select tag with 39 options, the max seems to be around 510px before it messes up.

你拥有的选择越多,选择的范围就越广,而且仍然可以很好地工作。如果我有一个带有39个选项的select标记,那么在它出错之前,最大值应该在510px左右。

On average, the max width that a select can handle seems to be approx 13px per option. So if you have a selector with 13 options, then the max is about 169px (13 * 13)

一般来说,select能够处理的最大宽度似乎是每个选项大约13px。如果你有一个13个选项的选择器,那么最大值是169px (13 * 13)

When you scroll to the 2nd option, the scrollTop is 14px and to the 3rd option, 28px. So each element that you scroll to is 14px. So as long as the width is less than the scrollHeight minus a certain number of pixels, it works... If you use the 13 pixels per option, it seems to work fine.

当你滚动到第二个选项时,scrollTop是14px,而第三个选项是28px。滚动到的每个元素都是14px。因此,只要宽度小于滚动高度减去一定数量的像素,就可以……如果您使用每个选项的13个像素,它似乎工作得很好。

So, you have 2 options.

你有两个选择。

  1. Make sure that the width of your select is less than 13 * the number of options
  2. 确保选择的宽度小于13 *选项的数量

OR

  1. Use javascript to get your desired behavior... I came up with a JsFiddle that works. And for those that like using jQuery, try this JsFiddle
  2. 使用javascript来获得所需的行为……我发明了一个能工作的小提琴。对于那些喜欢使用jQuery的人来说,试试这个JsFiddle。

You just have to listen to the keydown event and adjust the scroll so that the selected element is in view before it is selected.

您只需要监听keydown事件并调整滚动,以便选中的元素在被选中之前在视图中。

Also, in order to make the scrollByLines(numberOfLines) method work on the scroll element, it has to have the following style:

此外,为了使scrollByLines(numberOfLines)方法在滚动元素上工作,它必须具有以下样式:

overflow-y: scroll;

Here is a quick HTML document that works

这里有一个可以工作的快速HTML文档

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">

        // This happens on document load
        function myOnLoad() {

            // Get the selector element
            var mySelector = document.getElementById('mySelector');

            // If the selector is doomed to glitch out on us because it's wider than the max allowed width, we need to fix it
            if (mySelector.offsetWidth > 13 * mySelector.options.length) {

                // Figure out the pixels for a single scroll line
                mySelector.scrollByLines(1);
                var scrollLineHeight = mySelector.scrollTop;

                // Scroll back to the top
                mySelector.scrollTop = 0;

                // Add a keydown event listener so that we can scroll programatically before it messes up
                mySelector.addEventListener('keydown', function (e) {

                    // Only listen to up and down arrows
                    if (e.keyCode !== 38 && e.keyCode !== 40) {
                        return;
                    }

                    // Figure out where the selector is scrolled to
                    var scrollTop = this.scrollTop;
                    var scrolledToLine = parseInt(scrollTop / scrollLineHeight);

                    // If we hit the up arrow and the selected index is equal to the scrolled line, simply move us up by one
                    if (e.keyCode === 38 && this.selectedIndex === scrolledToLine) {
                        this.scrollByLines(-1);
                    }

                    // If we hit the down arrow and the selected index is equal to the scrolled line + the number of visible lines - 1, move us down by one
                    if (e.keyCode === 40 && this.selectedIndex === scrolledToLine + (this.size - 1)) {
                        this.scrollByLines(1);
                    }
                });
            }
        }
    </script>
</head>
<body onload="myOnLoad();">
<select size="5" name="selectMultiple" multiple="multiple" style="width:100%; overflow-y: scroll;" id="mySelector">
    <option value="0">line 0</option>
    <option value="1">line 1</option>
    <option value="2">line 2</option>
    <option value="3">line 3</option>
    <option value="4">line 4</option>
    <option value="5">line 5</option>
    <option value="6">line 6</option>
    <option value="7">line 7</option>
    <option value="8">line 8</option>
    <option value="9">line 9</option>
    <option value="10">line 10</option>
    <option value="11">line 11</option>
    <option value="12">line 12</option>
</select>
</body>
</html>

And here is the jQuery version:

下面是jQuery版本:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type="text/javascript">

        $( document ).ready(function() {

            // Get the selector element
            var mySelectorObj = $('#mySelector');
            var mySelector = mySelectorObj[0];

            // If the selector is doomed to glitch out on us because it's wider than the max allowed width, we need to fix it
            if (mySelector.offsetWidth > 13 * mySelector.options.length) {

                // Figure out the pixels for a single scroll line
                mySelector.scrollByLines(1);
                var scrollLineHeight = mySelector.scrollTop;

                // Scroll back to the top
                mySelector.scrollTop = 0;

                // Add a keydown event listener so that we can scroll programatically before it messes up
                mySelectorObj.on('keydown', function(e) {

                    // Only listen to up and down arrows
                    if (e.keyCode !== 38 && e.keyCode !== 40) {
                        return;
                    }

                    // Figure out where the selector is scrolled to
                    var scrollTop = this.scrollTop;
                    var scrolledToLine = parseInt(scrollTop / scrollLineHeight);

                    // If we hit the up arrow and the selected index is equal to the scrolled line, simply move us up by one
                    if (e.keyCode === 38 && this.selectedIndex === scrolledToLine) {
                        this.scrollByLines(-1);
                    }

                    // If we hit the down arrow and the selected index is equal to the scrolled line + the number of visible lines - 1, move us down by one
                    if (e.keyCode === 40 && this.selectedIndex === scrolledToLine + (this.size - 1)) {
                        this.scrollByLines(1);
                    }
                });
            }
        });
    </script>
</head>
<body>
<select size="5" name="selectMultiple" multiple="multiple" style="width:100%; overflow-y: scroll;" id="mySelector">
    <option value="0">line 0</option>
    <option value="1">line 1</option>
    <option value="2">line 2</option>
    <option value="3">line 3</option>
    <option value="4">line 4</option>
    <option value="5">line 5</option>
    <option value="6">line 6</option>
    <option value="7">line 7</option>
    <option value="8">line 8</option>
    <option value="9">line 9</option>
    <option value="10">line 10</option>
    <option value="11">line 11</option>
    <option value="12">line 12</option>
</select>
</body>
</html>

#1


1  

I think this is indeed some type of bug that has to do with the width of the select element vs the scrollHeight of the element.

我认为这确实是某种与select元素的宽度和元素的滚动高度有关的bug。

The more options you have, the wider it can be and still work fine. If I have a select tag with 39 options, the max seems to be around 510px before it messes up.

你拥有的选择越多,选择的范围就越广,而且仍然可以很好地工作。如果我有一个带有39个选项的select标记,那么在它出错之前,最大值应该在510px左右。

On average, the max width that a select can handle seems to be approx 13px per option. So if you have a selector with 13 options, then the max is about 169px (13 * 13)

一般来说,select能够处理的最大宽度似乎是每个选项大约13px。如果你有一个13个选项的选择器,那么最大值是169px (13 * 13)

When you scroll to the 2nd option, the scrollTop is 14px and to the 3rd option, 28px. So each element that you scroll to is 14px. So as long as the width is less than the scrollHeight minus a certain number of pixels, it works... If you use the 13 pixels per option, it seems to work fine.

当你滚动到第二个选项时,scrollTop是14px,而第三个选项是28px。滚动到的每个元素都是14px。因此,只要宽度小于滚动高度减去一定数量的像素,就可以……如果您使用每个选项的13个像素,它似乎工作得很好。

So, you have 2 options.

你有两个选择。

  1. Make sure that the width of your select is less than 13 * the number of options
  2. 确保选择的宽度小于13 *选项的数量

OR

  1. Use javascript to get your desired behavior... I came up with a JsFiddle that works. And for those that like using jQuery, try this JsFiddle
  2. 使用javascript来获得所需的行为……我发明了一个能工作的小提琴。对于那些喜欢使用jQuery的人来说,试试这个JsFiddle。

You just have to listen to the keydown event and adjust the scroll so that the selected element is in view before it is selected.

您只需要监听keydown事件并调整滚动,以便选中的元素在被选中之前在视图中。

Also, in order to make the scrollByLines(numberOfLines) method work on the scroll element, it has to have the following style:

此外,为了使scrollByLines(numberOfLines)方法在滚动元素上工作,它必须具有以下样式:

overflow-y: scroll;

Here is a quick HTML document that works

这里有一个可以工作的快速HTML文档

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">

        // This happens on document load
        function myOnLoad() {

            // Get the selector element
            var mySelector = document.getElementById('mySelector');

            // If the selector is doomed to glitch out on us because it's wider than the max allowed width, we need to fix it
            if (mySelector.offsetWidth > 13 * mySelector.options.length) {

                // Figure out the pixels for a single scroll line
                mySelector.scrollByLines(1);
                var scrollLineHeight = mySelector.scrollTop;

                // Scroll back to the top
                mySelector.scrollTop = 0;

                // Add a keydown event listener so that we can scroll programatically before it messes up
                mySelector.addEventListener('keydown', function (e) {

                    // Only listen to up and down arrows
                    if (e.keyCode !== 38 && e.keyCode !== 40) {
                        return;
                    }

                    // Figure out where the selector is scrolled to
                    var scrollTop = this.scrollTop;
                    var scrolledToLine = parseInt(scrollTop / scrollLineHeight);

                    // If we hit the up arrow and the selected index is equal to the scrolled line, simply move us up by one
                    if (e.keyCode === 38 && this.selectedIndex === scrolledToLine) {
                        this.scrollByLines(-1);
                    }

                    // If we hit the down arrow and the selected index is equal to the scrolled line + the number of visible lines - 1, move us down by one
                    if (e.keyCode === 40 && this.selectedIndex === scrolledToLine + (this.size - 1)) {
                        this.scrollByLines(1);
                    }
                });
            }
        }
    </script>
</head>
<body onload="myOnLoad();">
<select size="5" name="selectMultiple" multiple="multiple" style="width:100%; overflow-y: scroll;" id="mySelector">
    <option value="0">line 0</option>
    <option value="1">line 1</option>
    <option value="2">line 2</option>
    <option value="3">line 3</option>
    <option value="4">line 4</option>
    <option value="5">line 5</option>
    <option value="6">line 6</option>
    <option value="7">line 7</option>
    <option value="8">line 8</option>
    <option value="9">line 9</option>
    <option value="10">line 10</option>
    <option value="11">line 11</option>
    <option value="12">line 12</option>
</select>
</body>
</html>

And here is the jQuery version:

下面是jQuery版本:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type="text/javascript">

        $( document ).ready(function() {

            // Get the selector element
            var mySelectorObj = $('#mySelector');
            var mySelector = mySelectorObj[0];

            // If the selector is doomed to glitch out on us because it's wider than the max allowed width, we need to fix it
            if (mySelector.offsetWidth > 13 * mySelector.options.length) {

                // Figure out the pixels for a single scroll line
                mySelector.scrollByLines(1);
                var scrollLineHeight = mySelector.scrollTop;

                // Scroll back to the top
                mySelector.scrollTop = 0;

                // Add a keydown event listener so that we can scroll programatically before it messes up
                mySelectorObj.on('keydown', function(e) {

                    // Only listen to up and down arrows
                    if (e.keyCode !== 38 && e.keyCode !== 40) {
                        return;
                    }

                    // Figure out where the selector is scrolled to
                    var scrollTop = this.scrollTop;
                    var scrolledToLine = parseInt(scrollTop / scrollLineHeight);

                    // If we hit the up arrow and the selected index is equal to the scrolled line, simply move us up by one
                    if (e.keyCode === 38 && this.selectedIndex === scrolledToLine) {
                        this.scrollByLines(-1);
                    }

                    // If we hit the down arrow and the selected index is equal to the scrolled line + the number of visible lines - 1, move us down by one
                    if (e.keyCode === 40 && this.selectedIndex === scrolledToLine + (this.size - 1)) {
                        this.scrollByLines(1);
                    }
                });
            }
        });
    </script>
</head>
<body>
<select size="5" name="selectMultiple" multiple="multiple" style="width:100%; overflow-y: scroll;" id="mySelector">
    <option value="0">line 0</option>
    <option value="1">line 1</option>
    <option value="2">line 2</option>
    <option value="3">line 3</option>
    <option value="4">line 4</option>
    <option value="5">line 5</option>
    <option value="6">line 6</option>
    <option value="7">line 7</option>
    <option value="8">line 8</option>
    <option value="9">line 9</option>
    <option value="10">line 10</option>
    <option value="11">line 11</option>
    <option value="12">line 12</option>
</select>
</body>
</html>